这是 next-key lock 的退化形式,即对记录加排他锁(X)且对其前隙加间隙锁,常见于非唯一索引范围更新/删除时为防幻读而自动施加的混合锁。
“lock mode X locks rec but gap lock” 是什么锁?
这是 InnoDB 在死锁日志中对一种混合锁类型的简略描述,不是标准锁名,而是表示:当前事务持有的锁,既包含对记录本身(rec)的排他锁(X),又包含对该记录前一个间隙(gap)的间隙锁。
它常见于 UPDATE 或 DELETE 语句在非唯一索引(或无索引)上进行范围条件匹配时,InnoDB 为避免幻读而自动加上的组合锁。注意:这里 “rec but gap” 并非“记录锁 + 间隙锁”的简单叠加,而是指该锁在行为上同时覆盖记录和其前隙 —— 实际是 next-key lock 的一种退化表现,但因扫描过程中遇到已存在记录,导致间隙部分被“截断”。
典型触发场景包括:
- 执行
UPDATE t SET c=1 WHERE non_unique_idx > 10 AND non_unique_idx ,且索引值 15 已存在 - 在可重复读(RR)隔离级别下,
SELECT ... FOR UPDATE扫描非唯一二级索引范围 - 插入前做唯一性检查失败回滚后残留的锁状态(较少见)
为什么死锁日志里不直接写 “next-key lock”?
因为 InnoDB 日志只反映锁的最终生效形态,而非加锁意图。next-key lock 是理论模型(记录锁 + 间隙锁),但在实际加锁过程中,若目标记录已存在,InnoDB 可能只在该记录上加 X 锁,并在其前隙加间隙锁 —— 此时记录锁与间隙锁作用域不连续,日志就拆开描述为 “locks rec but gap lock”。
关键区别在于:
-
lock mode X locks rec→ 对具体聚集索引记录(或二级索引记录)加排他锁 -
lock mode X locks gap before rec→ 单独间隙锁(不锁记录) -
lock mode X locks rec but gap lock→ 同一操作引发两种锁,且间隙落在该记录之前(即:封锁区间为 (prev_rec, current_rec])
这个锁会阻塞哪些操作?
它会同时阻塞两类动作:
对记录本身的修改/删除: