作者:海滨的微博小窝 | 来源:互联网 | 2023-09-17 18:31
幻读是什么?
幻读是事务A在执行查询一条记录是否存在而进行插入时,在查询完毕,插入记录前的间隙中,事务B插入了这条数据,事务A在插入这条数据时会失败。幻读可能产生数据一致性问题,数据一致性不仅指的是数据库内部数据状态,也包含日志逻辑和数据的一致性。下图就说明下这个问题:
可以看到上图中A会话的语义是把d=5修改为100其最终提交是在t6时刻,B会话的语义是在t2时刻把id=0的c、d修改为5,C会话的语义是在t4时刻加入一条数据(1,1,5),修改id=1的c为5。但是其在binlog中写的顺序是B和C先执行,A最后执行,就会导致所有d=5的值修改为100,这不符合我们想要的数据。如果我们把所有扫描到的数据都加上了锁,C会话中的插入的数据原先不存在,所以不会阻塞住。
在InnoDB中引入了间隙锁(Gap Lock),即锁住两个记录之间的间隙。间隙锁+行锁被称为范围锁(next-key Lock)。间隙锁可以解决幻读的问题,那会带来其他的问题么?答案是会的,间隙锁会带来死锁的,比如下图中的操作:
A会话中的查询会给(5,10)加间隙锁,由于查询语句不会冲突,所以B会话也会在(5,10)加上间隙锁。这时B会话执行插入操作会阻塞,需要等待A会话中锁释放。而A会话执行插入操作也会阻塞,需要等待B会话中锁释放,这样死锁就形成了。
加锁规则:
加锁时,锁的类型是范围锁。只会把扫描到的数据加锁
索引上的等值查询,是唯一索引的话,范围锁退化成行锁
索引上的等值查询,向右遍历时,且最后一个值不满足等值条件时,范围锁退化成间隙锁
在上图的A会话中会锁住(5,10],(10,15)区间,但是由于>=10是等值查询,并且在唯一索引上,结合上面的加锁规则,会退化成行锁,只锁住连id=10这行记录。
在上图的A会话会锁住(10,15],(15,20)区间,结合加锁规则3,导致后面的B会话和C会话的操作阻塞。
这篇文章对幻读是什么?会产生何种问题然后怎么解决进行了学习,希望可以给读者分享更多的所学。