插入意向锁和间隙锁

插入意向锁(Insert Intention Lock)与间隙锁(Gap Lock)的区别
在 InnoDB 中,插入意向锁和间隙锁都是用于管理索引间隙(Gap)的锁机制,但它们的 设计目的、加锁行为 和 兼容性规则 有显著不同。以下是两者的核心区别:

  1. 定义与设计目标
锁类型 定义 设计目标
间隙锁(Gap Lock) 锁定索引记录之间的间隙(例如 (10, 20)),禁止其他事务在间隙内插入新数据。 防止幻读(Phantom Read),确保事务期间范围内数据的稳定性。
插入意向锁(Insert Intention Lock) 一种特殊的间隙锁,表示事务 计划在某个间隙插入数据,但尚未实际插入。 提高并发插入效率,允许不同事务在同一个间隙内插入 不冲突 的数据。
  1. 加锁时机与行为
锁类型 触发操作 加锁范围 锁行为
间隙锁 范围查询(如 SELECT ... WHERE id > 10) 锁定一个索引间隙(如 (10, 20)) 完全阻塞其他事务在间隙内插入数据。
插入意向锁 插入操作(如 INSERT INTO t VALUES (15)) 锁定目标插入位置的间隙(如 (10, 20)) 仅声明插入意图,不阻塞其他事务插入不同位置的记录(允许插入不冲突的值)。
  1. 兼容性规则
当前锁类型 请求的锁类型 是否兼容
间隙锁 插入意向锁 ❌ 不兼容(插入意向锁需等待间隙锁释放)
插入意向锁 插入意向锁 ✅ 兼容(允许不同事务在同一间隙插入不同数据,前提是插入的值不冲突)
间隙锁 间隙锁 ✅ 兼容(所有间隙锁本质是共享的)
  1. 示例场景
    场景 1:间隙锁阻塞插入
-- 事务 A
BEGIN;
SELECT * FROM t WHERE id > 10 AND id < 20 FOR UPDATE;  -- 加间隙锁 (10, 20)

-- 事务 B
INSERT INTO t (id) VALUES (15);  -- 阻塞!需等待事务 A 释放间隙锁

场景 2:插入意向锁允许并发插入

-- 事务 A
BEGIN;
INSERT INTO t (id) VALUES (15);  -- 对间隙 (10, 20) 加插入意向锁

-- 事务 B
BEGIN;
INSERT INTO t (id) VALUES (18);  -- 对同一间隙 (10, 20) 加插入意向锁,允许执行!
-- 两个插入操作不冲突,事务 B 不会被阻塞。

场景 3:间隙锁与插入意向锁的冲突

-- 事务 A
BEGIN;
SELECT * FROM t WHERE id > 10 FOR UPDATE;  -- 加间隙锁 (10, +∞)

-- 事务 B
BEGIN;
INSERT INTO t (id) VALUES (15);  -- 尝试对间隙 (10, +∞) 加插入意向锁,阻塞!
-- 事务 B 需等待事务 A 释放间隙锁。
  1. 死锁风险
    当多个事务同时持有间隙锁并尝试插入冲突的插入意向锁时,可能引发死锁:
-- 事务 A
BEGIN;
SELECT * FROM t WHERE id = 10 FOR UPDATE;  -- 加间隙锁 (prev, 10]

-- 事务 B
BEGIN;
SELECT * FROM t WHERE id = 20 FOR UPDATE;  -- 加间隙锁 (prev, 20]
INSERT INTO t (id) VALUES (15);            -- 尝试插入到事务 A 的间隙,被阻塞

-- 事务 A
INSERT INTO t (id) VALUES (25);            -- 尝试插入到事务 B 的间隙,死锁触发!
-- InnoDB 会自动回滚一个事务。

插入意向锁也是一种行级锁

行级锁的粒度分类
行级锁的粒度包括以下类型:

  • 记录锁(Record Lock):
    锁定单个索引记录(例如 id=10 的行)。
  • 间隙锁(Gap Lock):
    锁定索引记录之间的间隙(例如 (10, 20))。
  • Next-Key Lock:
    记录锁 + 间隙锁,锁定一个左开右闭区间(例如 (10, 20])。
  • 插入意向锁(Insert Intention Lock):
    一种特殊的间隙锁,表示事务计划在某个间隙插入数据。

插入意向锁的核心特点
锁定对象:索引间隙(例如 (10, 20)),而非具体行。
设计目标:

  • 提高并发插入效率,允许多个事务在 同一间隙 插入 不冲突的数据。
    兼容性:
  • 与普通间隙锁冲突(需等待间隙锁释放)。
  • 与其他插入意向锁兼容(允许插入不同值的记录)。

插入意向锁与间隙锁的关系

1.定义与锁定范围

  • 间隙锁(Gap Lock):
    锁定索引记录之间的 区间(例如 (10, 20)),禁止其他事务在此区间内插入新数据。
  • 插入意向锁(Insert Intention Lock):
    一种特殊的间隙锁,表示事务 计划在某个区间内插入数据,锁定的是 区间内的一个插入点。例如,插入 id=15 时,会声明对区间 (10, 20) 的插入意图,但实际锁定的位置是 15 所在的点。

2.核心区别

维度 间隙锁 插入意向锁
锁定目标 区间(如 (10, 20)) 区间内的一个插入点(如 15)
设计目的 防止其他事务插入数据 声明插入意图,提高并发插入效率
兼容性 与插入意向锁互斥 与其他插入意向锁兼容(不冲突插入)
加锁行为 完全禁止区间内的插入操作 允许不冲突的插入,仅阻塞冲突操作

3.互斥性与阻塞机制

  • 互斥性:
    如果一个事务持有某个区间的 间隙锁,其他事务无法在同一区间内获取 插入意向锁。例如:
    -- 事务 A
    SELECT * FROM t WHERE id > 10 FOR UPDATE;  -- 加间隙锁 (10, +∞)
    
    -- 事务 B
    INSERT INTO t (id) VALUES (15);  -- 尝试加插入意向锁,阻塞!
    
  • 非互斥场景:
    如果插入意向锁的目标点不在其他事务的间隙锁区间内,则不会被阻塞。例如:
    -- 事务 A
    SELECT * FROM t WHERE id BETWEEN 10 AND 20 FOR UPDATE;  -- 间隙锁 (10, 20)
    
    -- 事务 B
    INSERT INTO t (id) VALUES (25);  -- 插入意向锁 (20, +∞),允许执行!
    

4.插入意向锁的生成时机

  1. 检查间隙锁:
    执行插入操作时,InnoDB 会检查待插入记录的 下一条记录 是否已被加间隙锁。
    例如插入 id=15,需检查 id=20(当前索引中大于 15 的最小值)是否被加锁。
  2. 生成与等待:
    如果下一条记录被加了间隙锁,则生成一个 插入意向锁,并进入等待状态。
    若锁状态最终为 正常(GRANTED),表示插入成功;否则事务被阻塞,直到间隙锁释放。
    5.本质关系
  • 从属关系:
    插入意向锁是 间隙锁的子类型,但它仅表示插入意图,而非完全禁止插入。
  • 锁升级:
    当插入操作因间隙锁被阻塞时,插入意向锁会与间隙锁形成互斥,直到间隙锁释放后,插入意向锁才能生效。
posted @ 2025-02-26 16:40  lipu123  阅读(278)  评论(0)    收藏  举报