间隙锁只在rr隔离级别下生效,用于防止幻读,仅在当前读(如for update、update、delete)且使用索引进行范围查询或查询不存在记录时触发,锁定索引记录间的开区间。

间隙锁只在 RR 隔离级别下生效
MySQL 的间隙锁(Gap Lock)不是随时都起作用的。它只在 REPEATABLE READ 隔离级别下被 InnoDB 启用,且仅对「当前读」语句生效——也就是带 FOR UPDATE、LOCK IN SHARE MODE、UPDATE 或 DELETE 的查询。
在 READ COMMITTED 下,InnoDB 会退化为只对实际命中的记录加行锁,基本不加间隙锁(唯一索引等值查询失败时除外)。所以如果你观察不到间隙锁行为,先确认事务隔离级别:SELECT @@transaction_isolation;。
- RR 级别下,间隙锁是默认机制,用于防止幻读
- RC 级别下,即使写
SELECT * FROM t WHERE id > 10 FOR UPDATE,也不会锁 (10, +∞) 这个间隙 - 显式设置隔离级别:
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
哪些 SQL 会触发间隙锁?
不是所有带条件的 FOR UPDATE 都会触发间隙锁,关键看「是否扫描到空隙」以及「索引类型和查询方式」。
常见触发场景:
SELECT * FROM users WHERE age > 20 AND age —— 普通索引上的范围查询,必然加间隙锁,锁定 (20,30) 区间-
SELECT * FROM users WHERE id = 100 FOR UPDATE;—— 主键或唯一索引等值查询,但id=100不存在时,会锁住 (prev_id, next_id) 这个间隙 -
SELECT * FROM users WHERE name LIKE 'zhang%';—— 如果name有普通索引,前缀匹配仍属范围扫描,可能触发间隙锁 -
UPDATE users SET status=1 WHERE created_at > '2025-01-01';—— 范围更新,同样触发间隙锁(只要走的是普通索引)
反例: SELECT * FROM users WHERE id = 5 FOR UPDATE;(id 是主键,且该行存在)→ 只加记录锁,不加间隙锁。
间隙锁锁的是什么?不是记录,是“能插进去的地方”
间隙锁锁定的是索引中两个相邻值之间的开区间,比如索引值为 [10, 20, 30],那么间隙就是 (-∞, 10)、(10, 20)、(20, 30)、(30, +∞)。这些区间里没有真实数据,但可以插入新记录。
典型表现:
- 事务 A 执行
SELECT * FROM t WHERE id > 10 AND id → 锁住 <code>(10, 20) - 此时事务 B 尝试
INSERT INTO t (id, ...) VALUES (15, ...);→ 被阻塞 - 但
INSERT INTO t (id, ...) VALUES (10, ...);或(20, ...)不会被阻塞(它们落在已有记录上,由记录锁控制)
注意:间隙锁是「左开右开」区间,不包含端点;而临键锁(Next-Key Lock)是「左开右闭」,即 (10, 20],它 = 记录锁 + 前向间隙锁,是 InnoDB 默认使用的锁模式。
为什么线上容易因间隙锁卡死或死锁?
间隙锁本身不互斥——多个事务可以同时持有同一个间隙的间隙锁。但问题出在「间隙 + 记录」组合成的临键锁,以及不同事务扫描顺序不一致时的加锁竞争。
高频踩坑点:
- 没有索引的查询(如
WHERE status=1且status无索引)→ 全表扫描 → 实际上锁整个聚簇索引范围,效果接近表锁 - 范围查询条件太宽,比如
WHERE create_time > '2020-01-01'→ 锁住从某条记录到+∞的巨大间隙,后续插入全部被堵 - 两个事务分别执行
SELECT ... WHERE id > 100 FOR UPDATE和SELECT ... WHERE id > 90 FOR UPDATE,若扫描顺序/索引结构不同,可能形成循环等待 - 业务中大量使用
INSERT ... ON DUPLICATE KEY UPDATE,在唯一键冲突时也会隐式触发间隙锁(尤其当冲突发生在间隙内)
真正难排查的,往往不是“有没有锁”,而是“锁了多大一片”。查锁状态得看 INFORMATION_SCHEMA.INNODB_TRX 和 INNODB_LOCKS(MySQL 8.0+ 已移除后者,改用 performance_schema.data_locks),而不是只盯着 SQL 写法。











