MySQL 锁分类深度解析
候选人小周在美团二面中,面试官问:
"MySQL 有哪些锁?"
小周说:"有行锁和表锁。"
面试官追问:"行锁有哪些?表锁呢?"
小周说:"...行锁就是锁定行的,表锁就是锁定整张表的。"
面试官继续追问:"什么是间隙锁?什么是临键锁?"
小周彻底答不上来了。
【面试官心理】 这道题我用来测试候选人对 MySQL 锁机制的理解深度。能说出行锁和表锁的占 80%,能讲清间隙锁和临键锁的占 20%。锁机制是 MySQL 面试的难点,也是生产环境中死锁的根源。
一、锁的分类 🔴
1.1 按锁粒度分类
1.2 按锁属性分类
1.3 锁的兼容矩阵
二、行锁详解 🔴
2.1 行锁的实现
InnoDB 的行锁通过索引实现。如果没有索引,InnoDB 会锁定所有行(实质上是表锁)。
2.2 ❌ 错误理解
候选人原话:"InnoDB 的行锁是锁住数据行,所以只要操作不同行就不会冲突。"
问题诊断:
- 忽略了行锁是通过索引实现的
- 如果 WHERE 条件没有索引,会锁很多行甚至整表
- 索引失效时行锁可能变成表锁
生产环境中,经常发现"我的查询只更新一行,为什么锁了整张表?"的 bug。根因往往是 WHERE 条件的索引失效了,导致行锁升级为表锁。
三、间隙锁(Gap Lock)🔴
3.1 什么是间隙锁
间隙锁锁定的是索引树中的间隙,防止其他事务在这个间隙中插入数据。
3.2 间隙锁的作用
间隙锁的主要作用是防止幻读。
3.3 间隙锁的范围
四、临键锁(Next-Key Lock)🔴
4.1 什么是临键锁
临键锁 = 记录锁 + 间隙锁,即锁定一个索引记录和它前面的间隙。
4.2 临键锁的查询逻辑
4.3 InnoDB 的默认锁行为
在 REPEATABLE READ 隔离级别下,InnoDB 默认使用临键锁来防止幻读。
【面试官心理】 临键锁是 MySQL 锁机制中最难理解的部分。能说清楚"临键锁 = 记录锁 + 间隙锁"的候选人不到 20%,能解释清楚 InnoDB 默认使用临键锁的更少。这道题是 P7 的筛选器。
五、表锁详解 🟡
5.1 表锁的分类
5.2 MDL(元数据锁)
MySQL 5.5+ 引入了 MDL(元数据锁),用于保护表结构。
MDL 锁是 DDL 和 DML 之间的互斥锁,防止在修改表结构时读取不稳定的数据。
生产环境中,DDL 操作(如 ALTER TABLE)会加 MDL 排他锁,如果表有大量查询在执行,DDL 会等待,可能导致大量连接堆积。解决方案:使用 pt-online-schema-change 或 gh-ost 工具。
六、锁的查看与排查 🟡
6.1 查看锁信息
6.2 死锁示例
七、生产避坑 🟡
7.1 索引失效导致锁升级
7.2 长事务导致锁堆积
【面试官心理】 能说出"索引失效导致行锁变表锁"这个点的候选人,基本都有生产问题排查经验。这道题能完整回答的,基本都是 P7 水准。
八、面试追问链
第一层:MySQL 有哪些锁?
- 候选人:行锁、表锁、页锁
第二层:行锁是怎么实现的?
- 候选人:通过索引实现
第三层:什么是间隙锁?
- 候选人:锁定索引之间的间隙,防止幻读
第四层:什么是临键锁?
- 候选人:记录锁 + 间隙锁
第五层:REPEATABLE READ 下默认使用什么锁?
- 候选人:临键锁