1.检测 mysql 高并发可重复读隔离机制下 数据一致性 各

2019-03-06  本文已影响0人  阿洋691

建表

CREATE TABLE `test` (

`id` int(11)unsigned NOT NULL AUTO_INCREMENT,

`name` varchar(255)NOT NULL COMMENT '用户名称',

`score` int(11)NOT NULL DEFAULT '0' COMMENT '别名评分',

`card` varchar(255)not null comment ' 别名吧 ',

PRIMARY KEY (`id`),

)ENGINE=InnoDBDEFAULT CHARSET=utf8COMMENT='测试用户分数表';

1 场景一 (一个用户只能插入一条记录) 高并发情况下两个事务

t1

select * from test where name = '大毛'; 

如果不存在就插入

insert into test(name, score, card) value('大毛', 10,  '盒子精');

t2

select * from test where name = '大毛';

如果不存在就插入

insert into test(name, score, card) value('大毛', 10,  '盒子精');

先执行

t1.begin; 

t2.begin; 

t1.select * from test where name = '大毛';

t2.select * from test where name = '大毛';

t2.insert into test(name, score, card) value('大毛', 10,  '盒子精');

t1.insert into test(name, score, card) value('大毛', 10,  '盒子精');

t2.commit;

t1.commit;

此时有两条记录不可避免重复添加 可重复读避免不了这种情况 意料之中

删除表 改变下顺序重新试验下

t1.begin;

t2.begin; 

t1.select * from test where name = '大毛';

t2.select * from test where name = '大毛';

t2.insert into test(name, score, card) value('大毛', 10,  '盒子精');

t2.commit;

t1.select * from test where name = '大毛'; // 只是想重现一下 幻读的情况  但不知道是不是版本问题 并没有读取出结果很奇怪 我看了好多文章 以为可重复读可以出现幻读的情况的 可能我理解哪里有问题 查了下 事务隔离 级别 REPEATABLE-READ 没问题 (最后是理解错误, 幻读并不是指的这个 具体以后在实验)

t1.insert into test(name, score, card) value('大毛', 10,  '盒子精');

t1.commit;

删除表 测一下 查询插入sql语句 可不可以避免这个情况

t1.begin;

t2.begin; 

t1.select * from test where name = '大毛';

t2.select * from test where name = '大毛';

t2.insert into test(name, score, card) value('大毛', 10,  '盒子精');

t2.commit;

t1.select * from test where name = '大毛'; 

t1.insert into test(name, score, card) select '大毛', 10,  '盒子精' from dual where not exists (select * from test where name = '大毛' ) //并没有插入数据

t1.commit;

删除表 再次测试一下 两个事务都没有提交的情况下 查询插入 可不可以避免这个情况

t1.begin;

t2.begin; 

t1.select * from test where name = '大毛';

t2.select * from test where name = '大毛';

t2.insert into test(name, score, card) select '大毛', 10,  '盒子精' from dual where not exists (select * from test where name = '大毛' )

t1.insert into test(name, score, card) select '大毛', 10,  '盒子精' from dual where not exists (select * from test where name = '大毛' ) // 结果这个语句被阻塞了

t2.commit;

t1.commit;

插入查询这个写法完美避免 了这种情况

但是如果这样的 语句多了 可能阻塞 那么 他是 select * from test where name = '大毛' 针对这个一个条件阻塞的吗 还是只要类似的 插入2毛  大毛的也会被阻塞  突然好奇

顺便试验下下

删除表重建

t1.begin;

t2.begin; 

t1.select * from test where name = '大毛';

t2.select * from test where name = '大毛';

t2.insert into test(name, score, card) select '大毛', 10,  '盒子精' from dual where not exists (select * from test where name = '大毛' )

t1.insert into test(name, score, card) select '二毛', 10,  '盒子精' from dual where not exists (select * from test where name = '二毛' ) // 结果这个语句依然被阻塞了

t2.commit;

t1.commit;

结果好像有点小遗憾 要看情况使用;(具体原因可能需要了解mysql底层现实知识了)

下面测试是一下 更新操作

先查下库里数据

+----+--------+-------+-----------+

| id | name  | score | card      |

+----+--------+-------+-----------+

|  1 | 大毛  |    10 | 盒子精    |

|  2 | 二毛  |    10 | 盒子精    |

+----+--------+-------+-----------+

场景 给大毛加 10分 和一个加5分  同时这个执行两个操作 应该加15;结果是25分

t1.t2.begin;

t1.select * from test where name = '大毛'; 10分

t2.select * from test where name = '大毛';10分

t1.update test set score = 10 + 10 where name = '大毛';

t2.update test set score = 10 + 5 where name = '大毛';//这一条阻塞 不用试了 100%确定

t1.commit;

t2.commit;

select * from test where name = '大毛';

+----+--------+-------+-----------+

| id | name  | score | card      |

+----+--------+-------+-----------+

|  1 | 大毛  |    15 | 盒子精    |

结果明显不是我们想要的 前一个更新被后一个覆盖了 (这种情况有区别与 好多文章 写的 更新丢失)

换一个写法

先看下数据

select * from test;

+----+--------+-------+-----------+

| id | name  | score | card      |

+----+--------+-------+-----------+

|  1 | 大毛  |    15 | 盒子精    |

|  2 | 二毛  |    10 | 盒子精    |

+----+--------+-------+-----------+

开始

t1.t2.begin

t1.update test set score = score + 10 where name = '大毛';

t2.update test set score = score + 5 where name = '大毛';

t1.commit;

t2.commit;

查出来的结果是 30 是希望的结果

在换一种写法

先看下数据

select * from test;

+----+--------+-------+-----------+

| id | name  | score | card      |

+----+--------+-------+-----------+

|  1 | 大毛  |    30 | 盒子精    |

|  2 | 二毛  |    10 | 盒子精    |

+----+--------+-------+-----------+

开始

t1.t2.begin;

t1.select * from test where name = '大毛'; 30分

t2.select * from test where name = '大毛';30分

t1.update test set score = 30 + 10 where name = '大毛' and score = 30;

t2.select * from test where name = '大毛';30分

t2.update test set score = 30 + 5 where name = '大毛' and score = 30; //因为阻塞到上一个事物结束 所以 最后会更新失败 

t2.select * from test where name = '大毛';30分 //但是查询的依旧不是上一个事务结束的结果 (这个应该是可重复读机制隔离的原因)

t1.commit;

t2.commit;

暂时就到此结束了,.

半夜睡不着 无聊起来写一写 试一试, 做个日志

如果不小心 有别的小伙伴看到了, 可以解答讨论下的 不胜感激;

上一篇 下一篇

猜你喜欢

热点阅读