间隙锁解决幻读
面试官问:"MySQL 的可重复读是怎么解决幻读问题的?"
小张说:"用间隙锁。"
面试官追问:"间隙锁锁住的是什么?"
小张说:"锁住两条记录之间的空隙。"
面试官继续追问:"如果表里只有一条记录,间隙锁锁哪里?"
小张想了想:"...那没有空隙?"
面试官摇摇头。
这道题,考的是候选人对间隙锁和幻读关系的理解深度。知道"间隙锁能解决幻读"只是皮毛,知道"间隙锁锁住的是什么范围"和"为什么能防止幻读"才是真正理解。
一、幻读问题回顾 🔴
1.1 幻读的定义
幻读指的是同一事务内,两次执行相同的查询,结果集不一样(多了或少了行)。
1.2 幻读在快照读和当前读下的表现
关键结论:
- 快照读的幻读由 MVCC 解决(ReadView)
- 当前读的幻读由临键锁/间隙锁解决
1.3 ❌ 错误示范
候选人原话:"可重复读下没有幻读问题。"
问题诊断:不完全正确。快照读的幻读被 MVCC 解决,但当前读(FOR UPDATE)仍可能有幻读(除非用间隙锁)。
候选人原话 2:"间隙锁锁住的是行,不是空隙。"
问题诊断:混淆了记录锁和间隙锁。间隙锁只锁空隙,不锁记录。
【面试官心理】 这道题我会从快照读和当前读的区别切入。很多候选人知道"间隙锁解决幻读",但说不清楚是哪种读场景下的幻读。能区分 MVCC 和锁机制在幻读问题上的分工的候选人,才算真正理解。
二、间隙锁的工作原理 🔴
2.1 间隙锁锁住的是什么?
间隙锁锁住的是索引记录之间的空隙,目的是防止其他事务在这个空隙中插入新记录。
2.2 间隙锁的锁住范围
2.3 临键锁:记录锁 + 间隙锁
三、为什么间隙锁能防止幻读?🟡
3.1 当前读的场景
3.2 锁的范围取决于索引
3.3 唯一索引的特殊情况
四、生产避坑 🟡
4.1 无索引列的间隙锁灾难
⚠️
对没有索引的列执行 UPDATE/DELETE/SELECT FOR UPDATE,会导致 InnoDB 锁住全表。生产环境中,这种查询轻则导致大量锁等待,重则导致数据库连接耗尽。
4.2 范围查询的锁扩大
4.3 锁与死锁
间隙锁和间隙锁之间不互斥:
【面试官心理】 这道题我能从多个角度追问。比如:"为什么唯一索引等值查询能退化为记录锁?"能答出"因为唯一索引保证了不存在重复值,不需要锁间隙防止插入"的候选人,说明他对锁退化机制有深入理解。