Skip to content

间隙锁在哪个隔离级别?

约 661 字大约 2 分钟

MySQL腾讯

2025-03-13

⭐ 题目日期:

腾讯 - 2024/08/19

📝 题解:

间隙锁(Gap Lock)主要用于 可重复读Repeatable Read) 隔离级别,是 MySQL InnoDB 引擎防止幻读(Phantom Read)的核心机制之一。以下是详细说明:


1. 间隙锁的作用

  • 锁定范围:间隙锁锁定的是索引记录之间的“间隙”(即两个索引值之间的区间),而非具体的数据行。
  • 防止幻读:通过锁定可能插入新数据的范围,阻止其他事务在间隙内插入新记录,从而避免事务内多次查询结果集的行数变化。

示例: 假设表中有索引值 10, 20, 30,事务 A 查询 WHERE id > 15

  • 间隙锁会锁定区间 (10, 20)(20, 30),阻止其他事务插入 1525 等值。

2. 隔离级别与间隙锁的关系

img


3. Next-Key Lock:间隙锁的增强版

  • 定义:Next-Key Lock = 行锁(Record Lock) + 间隙锁(Gap Lock),锁定索引记录及其前面的间隙。
  • 作用:在可重复读级别下,既防止其他事务修改当前行,又阻止在范围内插入新数据。
  • 示例: 若事务 A 执行 SELECT * FROM table WHERE id = 20 FOR UPDATE
    • 锁定索引值 20(行锁)。
    • 锁定其前一个间隙 (10, 20)(间隙锁)。
    • 其他事务无法插入 id=15 或修改 id=20

4. 如何验证间隙锁的存在?

  • 场景模拟
    • 事务 A 执行范围查询并加锁:

    • BEGIN;
      SELECT * FROM user WHERE age BETWEEN 20 AND 30 FOR UPDATE;
    • 事务 B 尝试在间隙内插入数据:

    • INSERT INTO user (id, age) VALUES (5, 25);  -- 阻塞,直到事务 A 提交或超时
    • 结果:事务 B 被阻塞,证明间隙锁生效。


5. 注意事项

  • 仅针对非唯一索引:若查询条件使用唯一索引且精确匹配(如 WHERE id = 20),InnoDB 可能退化为行锁,无需间隙锁。
  • 显式禁用间隙锁
    • 设置隔离级别为 读已提交Read Committed)。
    • 设置 innodb_locks_unsafe_for_binlog = 1(但此参数在 MySQL 8.0 中已废弃)。
  • 性能影响:间隙锁会增加锁冲突概率,高并发写入场景可能引发死锁或性能下降。

总结

  • 间隙锁仅在可重复读Repeatable Read)隔离级别下默认启用,是 InnoDB 防止幻读的核心机制。
  • 若需避免间隙锁的副作用(如减少锁冲突),可降级至 读已提交Read Committed),但需容忍幻读风险。
  • 合理设计索引(如尽量使用唯一索引)能减少间隙锁的锁定范围,优化并发性能。