间隙锁锁定索引中相邻值之间的开区间(a,b),如(−∞,10)、(10,20)等,防止其他事务在该范围插入新记录;InnoDB通过临键锁(行锁+前向间隙锁)实现可重复读下的幻读防控。

间隙锁是InnoDB在可重复读(RR)隔离级别下防止幻读的核心机制,它不锁记录本身,而是锁定索引中两个相邻值之间的“空档”——也就是尚未存在的数据插入位置。
间隙锁锁的是什么范围
间隙锁作用于索引的有序结构,锁定的是开区间(a, b),即所有严格大于a、严格小于b的值。例如索引值为[10, 20, 30]时,存在的间隙包括:
- (−∞, 10)
- (10, 20)
- (20, 30)
- (30, +∞)
这些区间代表可能插入新记录的位置。间隙锁生效后,其他事务无法向其中插入满足条件的新行,比如在(10, 20)中插入id=15的记录就会被阻塞。
间隙锁如何配合行锁防止幻读
单独的行锁只能保护已有数据不被修改或删除,但对“新增”无能为力。InnoDB实际使用的是临键锁(Next-Key Lock),它是行锁与前向间隙锁的组合,形式为(a, b]——左开右闭。
- 查询 SELECT ... WHERE age BETWEEN 25 AND 35 FOR UPDATE 时,若当前有age=25、30、35三条记录,则不仅锁定这三行,还会锁定(−∞,25)、(25,30)、(30,35)、(35,+∞)中的相关间隙
- 重点在于:它把查询条件覆盖的整个索引范围都纳入保护,使其他事务无法在该范围内插入任何符合WHERE条件的新记录
- 这样事务内两次相同范围的当前读(如FOR UPDATE),结果集就始终一致,幻读自然消失
间隙锁只在特定操作中激活
它不是默认开启的全局锁,而是在满足以下条件时由InnoDB自动加锁:
- 事务隔离级别为可重复读(RR)或串行化(SERIALIZABLE)
- 执行的是当前读操作,包括 SELECT ... FOR UPDATE、SELECT ... IN SHARE MODE、UPDATE、DELETE
- 查询条件含范围谓词(如 >、
- 对应索引列存在有效索引,否则退化为表级锁或无法精确锁定间隙
快照读和当前读的区别决定是否依赖间隙锁
MySQL通过两种路径应对幻读:
- 快照读(普通SELECT):靠MVCC机制,读取事务启动时刻的ReadView,看到的是历史一致性视图,插入的新行对它不可见,无需间隙锁
- 当前读(带锁SELECT/UPDATE/DELETE):必须看到最新数据,因此需要间隙锁+行锁协同,确保读到的数据范围在事务期间稳定不变
换句话说,间隙锁是为“要改、要锁、要实时”的场景服务的,不是为所有查询兜底。










