事务讲到最后,面试官往往会把你从"隔离级别"拉到"线上事故":
- 为什么卡住?
- 为什么死锁?
- 为什么 RR 下会出现间隙锁?
你必须记住的 3 句话(面试直出):
- InnoDB 的锁本质是:为保证语义,在索引上加锁,不是在"表/行"这个抽象上加锁。
- RR 下为避免范围内插入导致语义破坏,会出现 Next-Key Lock(记录锁 + 间隙锁)。
- 死锁不是"代码写错了"这么简单,更多是 锁顺序不一致 + 范围条件/索引缺失扩大锁范围。
1. 先建立锁的主线:锁的是"索引范围"
常见锁类型(面试够用版):
- 记录锁(Record Lock):锁住某条索引记录
- 间隙锁(Gap Lock):锁住索引记录之间的间隙,防止插入
- Next-Key Lock:记录锁 + 间隙锁,锁住一个"半开区间"的范围
关键结论:
- 是否走索引,决定锁的粒度。
- 没有合适索引,可能导致更大的范围被锁(甚至看起来像"锁表")。
2. 为什么会有间隙锁:是为了保证 RR 的范围语义
你可以用这个典型场景解释:
- 事务 A:
SELECT ... FOR UPDATE WHERE age BETWEEN 10 AND 20 - 如果不锁间隙,事务 B 可以插入一条
age=15 - A 再次执行范围更新/校验时,语义就被破坏(出现"范围内新增")
因此 RR 下,当前读/范围修改可能引入:
- 间隙锁、Next-Key Lock
更精确的工程口径(避免被追问时说含糊):
- 间隙锁主要出现在 RR + 当前读/修改 + 范围扫描 这些组合里
- 如果能被 唯一索引等值命中,很多场景会退化成记录锁(锁范围更小)
- 一旦是 非唯一索引 、范围条件 、索引缺失导致扫描,锁范围就容易膨胀
面试加分表达:
- 间隙锁不是为了"防幻读这个词",而是为了"防止范围内出现新记录导致语义不一致"。
3. 死锁怎么来的:用"锁顺序"解释最稳
死锁的经典结构:
- T1 持有 A,等待 B
- T2 持有 B,等待 A
在 InnoDB 里常见触发点:
- 两个事务更新同一批行,但 更新顺序不同
- 范围条件导致锁集合不一致(或扩大锁范围)
- 二级索引更新会涉及主键索引回表锁定(锁链更复杂)
一个工程上最常见的死锁模型:
- 事务 1:先更新
id=1再更新id=2 - 事务 2:先更新
id=2再更新id=1
解决思路通常不是"加大超时",而是:
- 固定更新顺序(按主键升序)
- 缩小事务
- 确保条件走索引,减少锁范围
再补一组更"线上可落地"的降死锁动作(你可以按优先级讲):
- 固定访问顺序:同一批资源按主键/业务 key 排序后依次更新
- 把"先查再改"改为"条件更新" :把校验写进
UPDATE ... WHERE ...,减少锁持有时间与往返 - 避免范围大批量更新:拆批、按主键分页、并控制并发
- 补齐索引:让条件尽量走到"更小范围"的索引记录,减少 Next-Key 锁范围
- 只做兜底的重试:对死锁错误做幂等重试,但不把重试当根治
4. 最容易踩坑的 4 个点
-
坑 1:
SELECT ... FOR UPDATE以为只锁一行- 走范围条件/非唯一索引时可能锁范围(Next-Key)。
-
坑 2:缺失索引导致锁范围扩大
- 条件无法定位到小范围索引记录,锁住大片区间。
-
坑 3:在事务里做慢操作
- 事务越长,持锁越久,冲突越明显。
-
坑 4:批量更新/分页更新的锁冲突
- 大事务 + 范围扫描容易放大锁等待与死锁概率。
5. 线上排查手册:锁等待与死锁
5.1 锁等待(接口变慢/超时)
你要快速回答三个问题:
- 谁在等?
- 在等谁?
- 等的锁是什么范围?
常用手段:
SHOW PROCESSLIST:看到Waiting for ... lockSHOW ENGINE INNODB STATUS:看TRANSACTIONS与LATEST DETECTED DEADLOCKperformance_schema/sys库视图:定位阻塞链
落地判断:
- 如果阻塞链上"持锁者"的 SQL 很慢/事务很长,先把它当"长事务/慢 SQL"处理。
5.2 死锁(InnoDB 会主动回滚一方)
现象:
- 应用报错:
Deadlock found when trying to get lock; try restarting transaction
处理姿势:
- 第一时间取
SHOW ENGINE INNODB STATUS(死锁信息会被覆盖,别拖) - 看清楚:
- 哪两个事务
- 各自持有什么锁
- 各自等待什么锁
你在 status 里需要重点抓的"可还原信息"(面试/实战都加分):
- 两边事务的 SQL(到底是哪条语句触发)
- 锁的是哪个索引(主键/二级索引)
- 是等值还是范围(决定是否可能是 Next-Key)
- 两个事务的执行顺序(是否锁顺序相反)
工程修复优先级:
- 固定锁顺序(按主键排序更新)
- 缩小事务与批次
- 补索引/改查询条件,缩小锁范围
- 业务上允许时做幂等重试(只作为兜底,不是根治)
6. 自测清单(你要能顺口讲出来)
-
Q:InnoDB 的锁锁在哪里?
- A:锁在索引上;是否走索引决定锁粒度与范围。
-
Q:Next-Key Lock 是什么?
- A:记录锁 + 间隙锁,用于 RR 下的范围当前读/修改,保证范围语义。
-
Q:死锁怎么降低概率?
- A:固定锁顺序、缩短事务、让条件走索引缩小锁范围,必要时做幂等重试。
7. 30 秒背诵稿
InnoDB 为保证事务语义会在索引上加锁,常见有记录锁、间隙锁和 Next-Key Lock。RR 下范围当前读/修改为了防止范围内插入破坏语义,可能加 Next-Key 锁导致锁范围变大。死锁通常来自锁顺序不一致或索引缺失导致锁集合扩大,线上先用 processlist/innodb status/performance_schema 找到阻塞链和死锁双方,再通过固定更新顺序、缩短事务、补索引来根治。