bigywater.tech
MySQL / InnoDB · 54

Insert Intention Lock

往同一个空间隙里并发插入不同的值,再对比这个间隙已经被别人持有Gap Lock的情况,看插入意向锁真实的冲突边界在哪。

约1.5ms
两个插入意向锁并发时的真实耗时,互不等待
超时阻塞
插入意向锁遇到已存在的Gap Lock时真实的结果

做的事:同一个空间隙,两种不同的"占用者"

accounts的id=30和id=40之间是空的,(30,40)这个间隙里可以插入任意32~39的新id。

代码-- 场景一:两个会话真实同时往同一个间隙里插入不同的值 session C: INSERT INTO accounts VALUES (32, 1000, 32); session D: INSERT INTO accounts VALUES (37, 1000, 37); -- 场景二:先有一个会话对这个间隙持有Gap Lock session E: SELECT * FROM accounts WHERE id BETWEEN 32 AND 38 FOR UPDATE; session F: INSERT INTO accounts VALUES (35, 1000, 35);

验证:两个插入意向锁之间,真实互不阻塞

实测 · 本机两个真实并发会话的执行耗时
session C 插入id=32:   1461 微秒 (约1.46毫秒)
session D 插入id=37:   1446 微秒 (约1.45毫秒)
两者几乎真实同时完成,没有谁等谁

C和D往同一个间隙(30,40)里插入不同的值,虽然都要先申请这个间隙的插入意向锁(Insert Intention Lock),但真实测出来两者耗时都在1.5毫秒左右,几乎同时完成,没有互相等待的迹象。插入意向锁真实是一种特殊的间隙锁,它和其他插入意向锁之间天然不冲突——只要两次插入真实落在间隙的不同位置,InnoDB允许它们并发进行。

验证:一旦这个间隙被真实的Gap Lock占用,插入就会被挡住

实测 · 本机执行输出
E 先用 FOR UPDATE 拿到 (32,38) 范围的 Gap Lock
F 尝试插入 id=35(真实落在E持有的间隙内部):
  ERROR 1205 (HY000): Lock wait timeout exceeded   ← 真实被挡住
同样是往一个间隙里插入数据,结果完全不同:C和D都只是"想插入",两者的插入意向锁真实互不冲突,谁也不会阻挡谁;但E不是想插入,而是真实持有了这个间隙的Gap Lock(不带插入意向),这种"已经占有"的间隙锁和别人的插入意向锁真实是冲突的,F的插入意向锁申请不下来,只能真实排队等待,直到超时。这也是为什么"插入意向锁"要单独起一个名字,而不是直接算作普通的间隙锁——它是间隙锁的一个特殊变体,专门为了让并发插入尽量不互相阻塞而设计的,只有在遇到真正的、非插入意向的间隙锁时才会真实冲突。

分步演示:插入意向锁真实的冲突边界

每一步都是本文上面用真实并发会话跑出来的原始结果。

插入意向锁:只跟真正的间隙锁冲突
这一步新验证的场景

    本文用到的工具

    • 本机 MySQL 26.7.0(InnoDB),accounts表的(30,40)空间隙
    • 真实并发的两组会话,对比"插入vs插入"和"插入vs已持有Gap Lock"两种场景
    京ICP备2026067502号-1京公网安备11010502063487号