事务隔离级别(tx_isolation)
大部分为个人测试的结果和观点,有哪里不对的各位大佬帮指导下~谢啦~
mysql中有四个事务级别,每个事务级别都有相对应的数字编号和字符
级别 | symbol | 值 | 描述 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|---|---|---|
读未提交 | READ-UNCOMMITTED | 0 | 存在脏读、不可重复读、幻读的问题 | 是 | 是 | 是 |
读已提交 | READ-COMMITTED | 1 | 解决脏读的问题,存在不可重复读、幻读的问题 | 否 | 是 | 是 |
可重复读 | REPEATABLE-READ | 2 | mysql 默认级别,解决脏读、不可重复读的问题,存在幻读的问题。使用 MMVC机制 实现可重复读 | 否 | 否 | 是 |
序列化 | SERIALIZABLE | 3 | 解决脏读、不可重复读、幻读,可保证事务安全,但完全串行执行,性能最低 | 否 | 否 | 否 |
-
幻读
- 首先我们需要了解什么是幻读,什么场景中会发生?怎么解决和避免?
幻读的发生:A查询ID为1的数据不存在时,B在A查询后插入一条ID为1的数据并提交,此时A再插入数据则无法插入,A重新查询数据还是不存在,此时就产生了幻读
幻读的解决和避免:
1、A在查询第一条数据时加行锁
select * from user where id = 1 for update;
2、使用SERIALIZABLE事务级别杜绝幻读
- 实际上在我们绝大多数的业务场景中基本不会出现幻读
幻读复现(可以看到在第6点时依旧查询为空,此时就触发了幻读!
-
脏读
- 脏读实际上就比较好理解了
- 也就是A更新了数据,B查到了A更新后的数据,A把刚刚更新的数据回滚了,B查到的数据就称之为脏读
-
脏读如何发生:在RU级别事务中,A更新了ID为1的数据还未提交或回滚,此时B查询ID为1的数据时会直接查到A所更新后的数据,此时A回滚后,B所拿到的数据则为脏数据
脏读如何解决和避免:
1、用户B在执行查询前先进行锁行(在B用户这里这样操作个人觉得比较鸡肋)
select * from user where id = 1 for update;
2、更换其他三个事务级别,建议使用RR事务级别
脏读复现(可以看到B在第1/3/5条命令所拿到的数据有差别,如在两个用户在同一时间运行,会造成什么后果.)
-
不可重复读
- 具体不知如何讲解,可看下方的对比(实际上我也有些懵逼)
不可重复读复现(事务级别READ-UNCOMMITTED)可以看到A在没有提交或回滚事务前就可以查询到B所更新提交的数据
可重复读复现(事务级别REPEATABLE-READ)可以看到右边的会话在第2条和第4条执行之后的时候左边的会话查询到的数据时一致的
则需要左边的会话结束事务后才可查询到右边所更新的数据
参考资料:
https://segmentfault.com/a/1190000016566788?utm_source=tag-newest