MySQL的间隙锁(Gap Lock)是InnoDB引擎在可重复读(Repeatable Read)隔离级别下特有的锁机制,用于解决幻读问题。以下是间隙锁的触发条件及锁范围的分析:
一、间隙锁何时出现?
-
范围查询(Range Queries)
当执行范围查询(如SELECT ... WHERE id BETWEEN X AND Y FOR UPDATE
)时,InnoDB会对满足条件的已有记录加记录锁(Record Lock),同时对查询范围内的间隙(Gap)加间隙锁,防止其他事务插入新数据。 -
等值查询但记录不存在
当执行等值查询(如SELECT ... WHERE id = Z FOR UPDATE
),若目标记录不存在,InnoDB会对该值所在的间隙加间隙锁,阻止其他事务插入该值。 -
唯一索引的例外情况
如果使用唯一索引且等值查询的记录存在,InnoDB只会加记录锁,不会加间隙锁(因为唯一性保证了无需防幻读)。
二、间隙锁的锁定范围
间隙锁锁定的是索引记录的间隙区间,具体规则如下:
1. 索引结构示例
假设某表索引值为 [10, 20, 30]
,索引间隙划分为:
(-∞, 10)
(10, 20)
(20, 30)
(30, +∞)
2. 不同场景的锁范围
-
场景1:范围查询
SELECT * FROM table WHERE id > 15 AND id < 25 FOR UPDATE;
- 锁住间隙:
(10, 20)
和(20, 30)
(防止插入16~19
和21~29
的值)。 - 锁住记录:
20
(如果存在则加记录锁)。
- 锁住间隙:
-
场景2:等值查询(记录不存在)
SELECT * FROM table WHERE id = 25 FOR UPDATE;
- 锁住间隙:
(20, 30)
(防止插入25
)。
- 锁住间隙:
-
场景3:唯一索引的等值查询(记录存在)
SELECT * FROM table WHERE id = 20 FOR UPDATE;
- 仅锁记录
20
(不加间隙锁)。
- 仅锁记录
三、间隙锁与临键锁的关系
- 临键锁(Next-Key Lock) = 记录锁 + 间隙锁,锁住左开右闭区间(如
(10, 20]
)。 - 间隙锁是临键锁的“间隙部分”(如
(10, 20)
),不包含右侧记录。
四、注意事项
- 仅作用于索引
间隙锁基于索引,若无有效索引,InnoDB会退化为表锁。 - 显式关闭间隙锁
通过降低隔离级别至读已提交(Read Committed),或设置innodb_locks_unsafe_for_binlog=1
(不推荐),可禁用间隙锁。 - 死锁风险
间隙锁可能因事务互相等待插入权限而导致死锁。
总结
间隙锁在可重复读级别下,通过锁定索引间隙防止幻读。其范围由查询条件和索引结构共同决定,需结合具体场景分析锁区间。理解间隙锁机制对优化高并发事务场景至关重要。