3/04/2025

InnoDB 的 间隙锁(Gap Lock)

 


InnoDB 的 间隙锁(Gap Lock) 是 MySQL 在 可重复读(Repeatable Read) 隔离级别下为了解决幻读(Phantom Read)问题而引入的一种锁机制。它锁定的是索引记录之间的“间隙”,而不是数据记录本身,目的是防止其他事务在锁定的间隙范围内插入新的数据。

  1. 什么是间隙(Gap)
    假设表中存在索引值为 1, 3, 5 的记录,那么可能的间隙包括:

    • (-∞, 1)

    • (1, 3)

    • (3, 5)

    • (5, +∞)
      间隙锁会锁定这些区间,阻止其他事务在区间内插入新数据。

  2. 间隙锁的作用

    • 解决幻读问题:防止其他事务插入符合当前事务查询条件的新数据。

    • 保证范围查询的一致性:例如 SELECT ... WHERE id BETWEEN 10 AND 20,间隙锁会锁定 10 到 20 之间的所有间隙,即使某些值当前不存在。

  3. 与临键锁(Next-Key Lock)的关系

    • 临键锁 = 行锁(Record Lock) + 间隙锁(Gap Lock),例如锁定区间 (3, 5](包含现有记录 5 和其之前的间隙)。

    • InnoDB 默认使用临键锁来实现可重复读隔离级别。


触发场景

  1. 范围查询

    sql
    复制
    SELECT * FROM table WHERE id > 10 AND id < 20 FOR UPDATE;

    会锁定 (10, 20) 之间的所有间隙,阻止插入 11 到 19 的新数据。

  2. 唯一索引的非唯一查询
    即使使用唯一索引,若查询条件是非唯一值(如 WHERE col = 100,但 col 允许重复),也可能触发间隙锁。

  3. 未命中记录的查询

    sql
    复制
    SELECT * FROM table WHERE id = 15 FOR UPDATE;

    如果表中没有 id=15 的记录,会锁定 (10, 20) 的间隙(假设相邻记录为 10 和 20)。


间隙锁的特性

  1. 仅针对可重复读隔离级别
    在 读已提交(Read Committed) 级别下,InnoDB 会禁用间隙锁。

  2. 基于索引
    间隙锁依赖索引,如果查询未使用索引,InnoDB 会退化为锁全表(表锁或所有间隙)。

  3. 共享锁与排他锁

    • 共享间隙锁(S Gap Lock):允许其他事务读间隙,但禁止插入。

    • 排他间隙锁(X Gap Lock):禁止其他事务读或插入。


示例与影响

场景:事务 A 和事务 B 的冲突

  1. 事务 A 执行:

    sql
    复制
    SELECT * FROM users WHERE age BETWEEN 20 AND 30 FOR UPDATE;

    锁定 (20, 30) 之间的间隙。

  2. 事务 B 尝试插入:

    sql
    复制
    INSERT INTO users (age) VALUES (25); -- 被阻塞

    事务 B 必须等待事务 A 释放间隙锁。


注意事项

  1. 死锁风险
    间隙锁可能导致死锁。例如:

    • 事务 A 锁定 (10, 20),尝试插入 15

    • 事务 B 锁定 (5, 15),尝试插入 12
      两者互相等待对方释放间隙锁,导致死锁。

  2. 性能影响
    过大的间隙锁范围会降低并发性能,需合理设计索引和查询条件。

  3. 禁用间隙锁
    可通过将隔离级别降为 读已提交,或设置 innodb_locks_unsafe_for_binlog=1(不推荐,破坏一致性)

DDD各层的分工

 DDD架构层次 在DDD中,我们通常有以下几层: 用户界面/展示层:接收请求,展示结果 应用层:协调领域对象完成用户用例,不包含业务规则 领域层:包含业务逻辑和规则,领域模型 基础设施层:提供技术能力,如持久化、消息等 各层职责分工 1. 接口请求数据获取与拼装 用户界面/展示...