热门标签 | HotTags
当前位置:  开发笔记 > 后端 > 正文

mysql幻读是什么?会产生什么问题?怎么解决幻读?

幻读是什么?幻读是事务A在执行查询一条记录是否存在而进行插入时,在查询完毕,插入记录前的

幻读是什么?

幻读是事务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会话中锁释放,这样死锁就形成了。

间隙锁和范围锁的加锁规则

加锁规则:

  1. 加锁时,锁的类型是范围锁。只会把扫描到的数据加锁

  2. 索引上的等值查询,是唯一索引的话,范围锁退化成行锁

  3. 索引上的等值查询,向右遍历时,且最后一个值不满足等值条件时,范围锁退化成间隙锁

下面来贴出几个操作实例,可以自己测下:

在上图的A会话中会锁住(5,10],(10,15)区间,但是由于>=10是等值查询,并且在唯一索引上,结合上面的加锁规则,会退化成行锁,只锁住连id=10这行记录。

在上图的A会话会锁住(10,15],(15,20)区间,结合加锁规则3,导致后面的B会话和C会话的操作阻塞。

这篇文章对幻读是什么?会产生何种问题然后怎么解决进行了学习,希望可以给读者分享更多的所学。



推荐阅读
author-avatar
海滨的微博小窝
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有