MySQL的幻读

定义:

也就是同样的select读取sql语句读到的数据,后一次比前一次读到更多的数据行(事务在执行两句select语句中间时间,有其他事务往数据库中加入了数据行)

事务执行过程中单独给每一行加写锁并不能阻止幻读,因为事务不能给当前没有记录的行加锁,所以其他事务可以加入新的数据,那么前后两次select就可能查到多出的数据行。如下图所示:
请添加图片描述

幻读的解决办法:

使用next-key lock(间隙锁 Gap key + 行锁的合称),间隙所就是锁住相邻两行记录之间的空行(前开后闭区间)。比如:(0, 10],(10, 15], (15, +∞]。
请添加图片描述

next-key lock两阶段形成过程:先在(0,9]上加间隙锁,然后合并行锁10,得到(0,10]

间隙锁存在的问题是会引入死锁:

因为间隙锁不同于行锁,行锁是只有一个事务可以对该行加锁,但是无数据的间隙行上可以被多个事务加间隙锁。之后间隙锁和行锁会形成next-key lock,那么当一行空数据的间隙行同时在两个事务中形成了next-key lock的时候,两个事务都试图在该行插入数据,就会进入死锁。

根本原因:间隙锁共享加锁过程,但是独占更新过程。也就是说同一行可以被多个事务加间隙锁,但是间隙锁会和行锁进行结合形成next-key lock那么该行就只能被一个事务进行更新操作。由于间隙锁是两阶段形成的,所以如果第一阶段已经形成了间隙锁,就算没有融合行锁成为next-key lock,其他事务也不能对该事务上加间隙锁的行进行更新,就会形成事务之间的锁竞争,如下图所示:
请添加图片描述

间隙锁出现死锁的解决方法:

  1. MySQL的死锁检测会立即触发,回滚其中一个事务,但会影响并发度。
  2. 此外间隙锁只有在事务为可重复读的隔离级别下生效,如果使用已提交读则不存在间隙锁,当然也不会有他造成的死锁,问题是会出现幻读。

最后总结一下

  • MySQL只会对查询过程中扫描到的行加锁,锁的基本单位为next-key lock,满足优化条件则会降低锁粒度(可重复读);
  • 无论是不是唯一索引,MySQL都需要扫描到下一行不满足查询条件的记录才停止。(也就是说最后一条扫描记录肯定不满足查询条件);
  • 等值查询时MySQL对间隙锁的优化(降低锁粒度):当用唯一索引进行查询时,next-key lock会退化为行锁,不加间隙锁;当不是唯一索引时会退化为间隙锁,不包含查询到的行记录上的行锁。

参考文章:

https://time.1geekbang.org/column/article/75173

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值