间隙锁解决幻读深度解析
候选人小张在字节三面中,面试官问了一道 MySQL 深度题:
"什么是幻读?为什么会出现幻读?MySQL 是怎么解决幻读的?"
小张说:"幻读是同一事务两次查询结果不同,MySQL 通过锁机制解决。"
面试官追问:"具体是哪种锁?"
小张说:"行锁?"
面试官:"行锁能防止幻读吗?如果我两次查询之间有另一个事务插入了一条数据,行锁能挡住吗?"
小张答不上来了。
【面试官心理】 这道题我用来测试候选人对幻读机制的理解深度。能说出"幻读是两次查询结果数不同"的占 50%,能说出行锁挡不住新插入的占 20%,能说清间隙锁和临键锁的占 5%。幻读是 MySQL 并发控制的核心问题,能答对的候选人基本都理解 MVCC 和锁机制。
一、幻读的本质 🔴
1.1 幻读的定义
幻读(Phantom Read):同一事务内,两次相同的查询返回不同的行数(因为其他事务插入了新数据)。
1.2 幻读和不可重复读的区别
二、行锁为什么挡不住幻读 🔴
2.1 行锁只锁记录
2.2 ❌ 错误理解
候选人原话:"有了行锁,其他事务就不能修改数据了,所以不会有幻读。"
问题诊断:
- 行锁只锁住已存在的记录
- 新插入的数据不受已有行锁影响
- 必须锁定"记录之间的间隙"才能防止插入
三、间隙锁如何防止幻读 🔴
3.1 间隙锁的原理
间隙锁(Gap Lock)锁定的是索引树中记录之间的间隙,防止其他事务在这个间隙中插入新记录。
3.2 间隙锁的工作示意图
3.3 间隙锁的锁定范围
间隙锁只在 REPEATABLE READ 隔离级别下生效。在 READ COMMITTED 级别下,间隙锁只锁定等值查询的精确位置,不锁定范围。
四、Next-Key Lock:临键锁 🔴
4.1 临键锁 = 记录锁 + 间隙锁
MySQL InnoDB 使用临键锁(Next-Key Lock)来解决幻读。
4.2 临键锁的查询过程
4.3 临键锁的边界情况
五、不同隔离级别下的幻读处理 🟡
5.1 READ COMMITTED
5.2 REPEATABLE READ
【面试官心理】 这张表是面试必考点。能完整说出的占 60%,能解释为什么 RC 级别下不能防止幻读的占 20%,能说出临键锁在 RC 级别下退化为记录锁的占 5%。
六、生产避坑 🟡
6.1 间隙锁导致的锁等待
6.2 唯一索引的间隙锁行为
6.3 监控间隙锁
【面试官心理】 能说出"唯一索引的等值查询不锁定间隙"的候选人,基本都研究过 MySQL 锁机制的源码。这是 P7 的水准。
七、面试追问链 🟡
第一层:什么是幻读?
- 候选人:两次查询结果数不同
第二层:为什么行锁挡不住新插入的数据?
- 候选人:行锁只锁记录,锁不住间隙
第三层:间隙锁是怎么工作的?
- 候选人:锁定记录之间的间隙,防止插入
第四层:临键锁是什么?它和间隙锁是什么关系?
- 候选人:临键锁 = 记录锁 + 间隙锁
第五层:为什么唯一索引的等值查询不需要间隙锁?
- 候选人:唯一索引保证了不会有重复值,间隙锁是多余的