这篇文章是学习极客时间专栏《MySQL 实战 45 讲》的笔记,加上我个人的一些理解,具体细节可以去读这个专栏。我们知道行锁只能锁住已经存在的行,并不能阻止插入新的行,如果同一个事务的两次查询中间其他事务插入了新的行,后一次查询就可能看到前一次查询没有看到的行,这就是幻读(Phantom Read)。需要注意的是,在可重复读隔离级别下,普通的查询是快照读,不会看到其他事务插入的数据,只有当前读才可能出现幻读。
加锁规则
为了解决幻读的问题,InnoDB 存储引擎引入了间隙锁(Gap Lock),锁住的是两个值之间的间隙。与行锁不同的是,跟间隙锁存在冲突关系的是“往这个间隙中插入行”的操作,间隙锁之间是不存在冲突的。间隙锁和行锁合称 Next-Key Lock,每个 Next-Key Lock 都是一个前开后闭区间,下面是《MySQL 实战 45 讲》中总结的加锁规则“两个原则、两个优化和一个 Bug”:
- 原则 1:加锁的基本单位是 Next-Key Lock
- 原则 2:查询过程中访问到的对象才会加锁
- 优化 1:索引上的等值查询,给唯一索引加锁时,Next-Key Lock 退化为行锁
- 优化 2:索引上的等值查询,向右遍历且最后一个值不满足等值条件时,Next-Key Lock 退化为间隙锁
- Bug:唯一索引上的范围查询会访问到不满足条件的第一个值为止