Mysql 幻读&Next Key Lock详解

什么是幻读

幻读的定义是指,一个事务开启后,执行前后两次查询,两次查询中出现了新的数据,幻读仅针对数据的新增。

比如: 表t中,id为主键,目前有数据1,5,10,20四条。

开始一个事务A,前后两次执行 select * from t where id < 10 for update;

开启一个事务B,在事务A第二次执行查询前,执行insert into t values( 2,...); 并提交事务(请暂时忽略这里能否成功执行!)。

此时在RC、RR隔离级别下都会导致事务A第二次查询能够查询到 事务B新增的数据 id = 2。

RC级别下能够看到不同结果就不做解释了。

对于RR隔离级别下,有了MVCC版本控制为什么还能读取到不同的结果呢?

这里要归功于 "for update"。

"for update" 会将快照读变为当前读,在当前读场景中,会自动读取最新的数据,而非快照数据。

思考:

  1. 是不是加锁就会变成当前读?

  2. lock in share mode 会将快照读变为当前读么?

  3. 普通 select 语句会加锁么?

  4. 普通update、insert、delete语句会加锁么?

TODO

分析一下,锁与当前读关系。了解什么情况下会加锁。了解 意向锁、共享锁、排它锁区别及各自在什么情况下使用。

行锁

行锁的概念都清楚,这里就不做补充了。

间隙锁 & Next Key Lock

间隙锁实际上是指一个区间。

幻读的危害

我们都知道,InnoDB 在RR事务隔离级别下解决幻读问题就是通过Next Key Lock (间隙锁+行锁)来实现的。而且,很多地方也有提到,如果对于读一致性要求不高的场景可以考虑使用RC隔离级别,允许幻读的发生。

那么幻读到底有什么影响或者危害呢?为什么一定要解决幻读?

还是上边说的那个实例,略微改动:

比如: 表t中,id为主键,目前有数据1,5,10,20四条。

开始一个事务A,前后三次分别执行

  1. select * from t where id < 10;

  2. update t set a = 5 where id < 10;

  3. select * from t where id < 10;

开启一个事务B,在事务A执行update前,执行insert into t values( 2,...); 并提交事务。

此时我们知道,事务A中第二次查询能够查到 事务B新增的数据,也就是产生了幻读。那么,按照SQL执行的顺序来说,事务B

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容