1.检测 mysql 高并发可重复读隔离机制下 数据一致性 各
建表
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;
暂时就到此结束了,.
半夜睡不着 无聊起来写一写 试一试, 做个日志
如果不小心 有别的小伙伴看到了, 可以解答讨论下的 不胜感激;