间歇锁是InnoDB在可重复读下为防止幻读而锁定索引间隙的机制,如执行select … for UPDATE WHERE id BETWEEN 2 AND 8时会锁定(1,5)和(5,10)间隙,阻止其他事务插入新行;其在范围查询、非唯一索引行锁等场景触发,通过封锁插入保障一致性,但降低并发并增加死锁风险,仅在RR级别生效;可通过优化索引、使用等值查询、调整隔离级别至RC或缩短事务来减少影响。

mysql的间歇锁(Gap Lock)是InnoDB存储引擎在可重复读(REPEATABLE READ)隔离级别下用来防止幻读的一种重要机制。它并不是锁定某一行数据,而是锁定索引记录之间的“间隙”,从而阻止其他事务在这个范围内插入新的记录。理解间歇锁的特性对避免死锁、提升并发性能至关重要。
什么是间歇锁
间歇锁作用于索引记录之间的间隙,或者在第一个索引记录之前、最后一个索引记录之后的区间。它不锁定记录本身,而是锁定一个范围,防止其他事务向该范围插入新行。
例如,若表中存在主键为1、5、10的记录,那么(1,5)和(5,10)之间的区间就是可能被间歇锁锁定的区域。如果一个事务执行了SELECT … FOR UPDATE WHERE id BETWEEN 2 AND 8,InnoDB会锁定(1,5)和(5,10)这两个间隙,防止其他事务插入id=3或id=7这样的记录。
间歇锁的触发条件
间歇锁主要在以下场景中出现:
- 使用范围条件加锁时:如SELECT * FROM t WHERE id > 10 FOR UPDATE,InnoDB不仅会锁定满足条件的记录,还会锁定后续的间隙,防止新记录插入导致幻读。
- 唯一索引的范围查询:即使查询的是唯一索引,只要不是等值查询(如WHERE id > 10),也会使用间歇锁。
- 非唯一索引上的行锁通常伴随间歇锁:在普通索引上进行精确匹配时,InnoDB可能会使用“记录锁+间歇锁”组合成“临键锁”(Next-Key Lock),即Record Lock + Gap Lock。
注意:等值查询且命中唯一索引(如主键)时,InnoDB只加记录锁,不会加间歇锁,因为此时可以确定不存在幻读风险。
间歇锁的作用与局限性
间歇锁的核心目标是解决“幻读”问题。通过封锁插入操作,确保在同一事务中多次执行相同范围查询时结果一致。
但间歇锁也带来了一些副作用:
- 降低并发性:多个事务可能因争夺同一间隙而阻塞,尤其在高并发插入场景下容易引发锁等待。
- 死锁风险增加:两个事务分别持有不同区间的间歇锁,并试图插入对方锁定的间隙时,可能发生死锁。
- 仅在RR隔离级别生效:在读已提交(READ COMMITTED)级别下,InnoDB通常不使用间歇锁,因此无法避免幻读。
如何减少间歇锁的影响
虽然间歇锁有助于一致性,但在某些场景下可以通过策略优化其影响:
- 合理设计索引:避免全表扫描,确保查询能快速定位到具体记录,减少锁住大范围间隙的可能性。
- 尽量使用等值查询:相比范围查询,等值查询在唯一索引上不会产生间歇锁。
- 调整隔离级别:如果应用可以容忍一定程度的幻读,可将隔离级别设为READ COMMITTED,此时InnoDB通常只加记录锁。
- 控制事务粒度:缩短事务执行时间,尽快提交,减少锁持有时间。
基本上就这些。间歇锁是InnoDB实现MVCC和一致性读的重要补充机制,虽然增加了复杂度,但在多数OLTP场景中利大于弊。关键在于理解其行为模式,并结合实际业务合理设计SQL与事务逻辑。