MySQL Insert Intention Lock 插入意向锁是什么

MySQL锁系列|插入意向锁完整详解

前置阅读:Gap间隙锁、Next‑Key Lock临键锁

一、什么是插入意向锁 Insert Intention Lock

插入意向锁是 InnoDB 在执行 INSERT 插入前自动施加的一种特殊的间隙锁(Gap Lock)

⚠️注意:名字带"意向",它不是表级的 IS/IX意向锁 ,属于行锁体系,作用于索引间隙。

生效前提:InnoDB、RR可重复读隔离级别;RC隔离级别关闭Gap锁,也就不存在插入意向锁。

作用:标记当前事务打算在某个索引间隙插入新数据

  • 多个事务向同一个间隙插入不同索引值时,插入意向锁互相兼容,可以并发插入,不会互相阻塞,提升插入并发性能。
  • 如果该间隙已经被其他事务持有 Gap间隙锁 / Next‑Key临键锁,插入意向锁会被阻塞,必须等待间隙锁释放,以此保护幻读不发生。

二、触发时机

执行INSERT语句时,InnoDB内部流程:

  1. 定位待插入记录在B+树索引中的间隙位置
  2. 尝试获取该间隙的插入意向锁
  3. 如果间隙被Gap/Next‑Key锁占用,INSERT阻塞等待;间隙空闲则获取成功
  4. 成功之后,对真正插入的数据行,加Record X排他行锁
  5. 事务提交,锁全部释放

普通快照读SELECT不会产生;UPDATE / DELETE / SELECT ... FOR UPDATE也不会产生插入意向锁,只有INSERT才会生成

三、锁兼容性矩阵

锁类型 插入意向锁 Gap间隙锁 / Next‑Key临键锁 Record S/X行锁
插入意向锁 ✅兼容 ❌互斥阻塞 ✅兼容

重点理解两点:

  1. 插入意向锁与插入意向锁互相兼容:多个事务可以同时拿到同一个间隙的插入意向锁,只要插入主键/索引值不一样,可以并发插入成功,不会阻塞。
  2. 插入意向锁 和 Gap锁、Next‑Key临键锁互斥:只要间隙被别人加了间隙锁,所有INSERT往这个间隙插入全部阻塞等待,这是RR防止幻读的核心机制。

示例:索引已有 1,5,间隙 (1,5)

  • 事务A:插入 id=2
  • 事务B:插入 id=3
    两个事务同时获取间隙(1,5)的插入意向锁,互不阻塞,可以同时完成插入。

如果事务C先执行select ... for update,给间隙(1,5)加上Gap锁;那么A、B的INSERT全部阻塞。

四、实战演示

测试表

sql 复制代码
CREATE TABLE t_lock(
  id INT PRIMARY KEY AUTO_INCREMENT,
  name VARCHAR(32)
);
INSERT INTO t_lock(name) VALUES('A'),('E');
-- id:1,5;间隙 (1,5)

场景1:间隙持有临键锁,INSERT被阻塞

会话A

sql 复制代码
BEGIN;
-- id=2不存在,唯一索引等值查询查无数据,退化为Gap锁,锁住间隙 (1,5)
SELECT * FROM t_lock WHERE id=2 FOR UPDATE;

此时间隙(1,5)被加上Gap间隙锁。

会话B

sql 复制代码
BEGIN;
-- 尝试插入id=3,需要获取间隙(1,5)插入意向锁,和Gap锁冲突,直接阻塞
INSERT INTO t_lock(id,name) VALUES(3,'C');

查看锁信息:

sql 复制代码
SELECT ENGINE_TRANSACTION_ID,LOCK_TYPE,LOCK_MODE,LOCK_TABLE,LOCK_DATA
FROM performance_schema.data_locks;
  • 会话A锁:LOCK_MODE: X,GAP Gap间隙锁
  • 会话B锁:LOCK_MODE: X,INSERT_INTENTION 插入意向锁,状态为WAITING等待中

会话A执行COMMIT;释放Gap锁,会话B立刻完成插入。

场景2:同一间隙,多个INSERT并发插入互不阻塞

会话A:

sql 复制代码
BEGIN;
INSERT INTO t_lock(id,name) VALUES(2,'B');

会话B:

sql 复制代码
BEGIN;
INSERT INTO t_lock(id,name) VALUES(3,'C');

A、B都获取间隙(1,5)插入意向锁,互相兼容,不会阻塞,两个insert都正常执行。

只有插入完全相同唯一键值时,才会报唯一键冲突报错,这是约束校验,不是锁阻塞。

五、RC隔离级别下没有插入意向锁

RC读已提交隔离级别:

  1. Gap间隙锁、Next‑Key临键锁全部关闭
  2. 插入意向锁也随之消失
  3. INSERT只会对插入行加Record X记录锁,间隙没有任何锁保护
  4. 并发插入性能更高,但当前读会出现幻读现象。

很多生产环境把隔离级别改为RC,就是为了消除Gap锁+插入意向锁带来的大量INSERT阻塞问题。

六、线上典型坑点与死锁案例

坑1:看不到insert语句,但是大量insert阻塞等待

现象:业务大量INSERT慢、堆积,但是没有慢SQL,也没有update/delete长事务。

根因:某个长事务执行for update / update / delete产生Gap锁/Next‑Key锁,锁住索引间隙,所有落在该间隙的INSERT全部等待插入意向锁释放。

✅排查:查询performance_schema.data_locks看是否存在X,GAP间隙锁,找到持有Gap锁的长事务。

坑2:插入意向锁参与死锁(经典死锁场景)

复现流程:

表数据 id:1, 10

会话A:

sql 复制代码
BEGIN;
SELECT * FROM t_lock WHERE id=5 FOR UPDATE; -- 查无数据,加Gap锁 (1,10)

会话B:

sql 复制代码
BEGIN;
INSERT INTO t_lock(id,name) VALUES(3,'B'); -- 获取插入意向锁,等待A释放Gap锁

会话A:

sql 复制代码
INSERT INTO t_lock(id,name) VALUES(4,'A'); -- A现在尝试插入4,也需要获取本间隙插入意向锁,等待B

循环等待:B等A的Gap锁;A等B的插入意向锁 → 触发死锁,InnoDB自动回滚其中一个事务
关键点:同一个事务,自己持有某个间隙Gap锁,自己也不能往这个间隙做INSERT,同样会等待,产生死锁。

坑3:误以为INSERT不会加锁

INSERT不是完全无锁:RR下INSERT会加插入意向锁,同时对新行加X记录锁;长事务不commit,插入的行X锁也会持续持有。

七、常见误区澄清

❌误区1:插入意向锁是表级IS/IX意向锁

完全两码事。IS/IX是表锁层面;插入意向锁属于行锁‑间隙锁体系。

❌误区2:插入意向锁会阻塞其他INSERT

插入意向锁之间互相兼容;只有遇上Gap锁、临键锁才阻塞。

❌误区3:RC隔离级别也会产生插入意向锁

RC关闭Gap锁机制,不会产生插入意向锁。

❌误区4:INSERT一定会产生插入意向锁

INSERT需要定位到索引间隙才会生成;RC模式无;如果索引不存在间隙,也不会触发。

❌误区5:同一个事务持有Gap锁,可以直接往该间隙INSERT

不行,自己持Gap锁,自己INSERT同样需要获取插入意向锁,会等待,极易死锁。

八、总结

  1. Insert Intention Lock插入意向锁,是RR级别下INSERT产生的特殊间隙锁,标记事务有插入意图,RC隔离级别不存在。
  2. 插入意向锁之间互相兼容,支持多事务同一间隙并发插入不同索引值,提升插入性能;但与Gap锁、Next‑Key临键锁互斥。
  3. 核心职责:兼顾并发插入性能,同时配合Gap锁阻止幻读;间隙一旦被Gap锁锁住,所有INSERT全部阻塞。
  4. 线上故障特征:大量INSERT阻塞等待,根源往往是长事务产生了Gap/Next‑Key锁;同一个事务持有Gap锁又执行INSERT会触发死锁。
  5. 优化方案:优先使用RC隔离级别消除间隙锁体系;避免长事务执行当前读(for update/update/delete)缩小锁范围;加锁SQL尽量走唯一索引,触发锁退化减少Gap锁产生。

MySQL锁系列全部完结:全局锁、MDL元数据锁、S表读锁、X表写锁、IS意向共享锁、IX意向排他锁、Record S/X行锁、Gap间隙锁、Next‑Key临键锁、Insert Intention插入意向锁。

相关推荐
两点王爷8 分钟前
PostgreSQL 常用 SQL 语句与 GIS 相关函数详解
数据库·后端
两点王爷18 分钟前
PostgreSQL 好用又独特的特性与空间函数
数据库
梦帮科技21 分钟前
AI 音乐产品的发布工程:验证门、数据发布、回滚与生产运维纪律
数据结构·数据库·架构·node.js·音视频·动态规划·推荐算法
TDengine (老段)2 小时前
TDengine 常见问题 TOP3
大数据·数据库·物联网·时序数据库·tdengine·涛思数据
螺蛳粉 螺蛳粉5 小时前
MySQL 分布式集群系列 · 第五篇——全方位对比:NDB、MGR、主从复制、分库分表怎么选?
数据库·分布式·mysql
泡泡鱼(敲代码中)6 小时前
MySQL 学习笔记:DCL、函数与约束 —— 安全、效率、完整性的三板斧
开发语言·笔记·sql·学习·mysql·gitee
这个DBA有点耶9 小时前
从OLTP到OLAP到HTAP:数据库负载分类的技术演进与选型指南
数据库·mysql·架构
YangYang9YangYan10 小时前
商业数据分析校招项目怎么选,附项目设计与简历包装思路
大数据·数据库·数据分析
李白客10 小时前
数据库培训怎么选?零基础到DBA的学习路线与机构认证对比(2026)
数据库·学习
shark-chili11 小时前
关于AI辅助编程的认知
数据库·人工智能·redis·macos·缓存