意向锁本身不阻塞任何操作,其唯一作用是让表级锁能快速判断表中是否存在行锁:事务加行锁前先加意向锁(is/ix),表锁申请时只需检查意向锁而非逐行扫描,大幅提升性能。

意向锁本身不阻塞任何操作,它的唯一作用是让表级锁能快速判断:当前有没有人在对这张表的某些行加行锁。
为什么需要意向锁?
InnoDB 同时支持行锁和表锁。如果没有意向锁,当一个事务想对整张表加 X(排他)表锁时,就必须扫描全表所有行锁状态,确认没人正在锁某几行——这开销太大。
有了意向锁,只需检查表上是否存在 IS 或 IX 锁:
-
IS(Intention Shared)表示“我准备给某些行加共享锁(S 锁)” -
IX(Intention Exclusive)表示“我准备给某些行加排他锁(X 锁)”
比如:事务 A 正在对 t1 表中 id=5 的行加 X 锁,它会自动在 t1 表上加 IX 锁;此时事务 B 想对 t1 加 X 表锁,发现已有 IX,立刻拒绝,无需查行。
意向锁和表锁的兼容性怎么判断?
MySQL 内部有一张兼容性矩阵,核心规则就两条:
-
IS与IS、S、IX兼容(允许并发读) -
IX与IX、IS、X不兼容(X表锁不能和任何意向锁共存)
注意:IX 和 S 表锁是兼容的——因为 S 表锁只读,不影响别人对部分行加写锁;但 IX 和 X 表锁互斥,因为 X 表锁要求整表独占。
你可以用 SELECT * FROM performance_schema.data_locks; 查看当前意向锁状态,其中 LOCK_TYPE = 'TABLE' 且 LOCK_MODE 包含 INTENTION 的就是。
什么时候会自动加意向锁?
你不需要手动加,只要执行以下任一操作,InnoDB 就会隐式加对应意向锁:
- 执行
SELECT ... LOCK IN SHARE MODE→ 加IS - 执行
SELECT ... FOR UPDATE或任何UPDATE/DELETE→ 加IX - 执行
INSERT(即使没显式加锁)→ 也会加IX,因为可能触发唯一键检查或外键约束校验
常见误区:认为只有显式加锁才触发意向锁。实际上,只要语句涉及行级锁机制(哪怕只是潜在可能),InnoDB 就会先申请意向锁。
容易忽略的细节
意向锁是表级锁,但它不阻止其他事务对同一张表做 DML —— 它只影响表级锁(如 LOCK TABLES t1 WRITE)或 DDL(如 ALTER TABLE)的获取时机。
真正容易被绕过的点是:当你看到 LOCK WAIT 等待时,别只盯着行锁,先查 performance_schema.data_locks 里有没有未释放的 IX 锁卡住了 DDL;或者在备份脚本里用了 FLUSH TABLES WITH READ LOCK,却发现业务更新卡住,大概率是某个长事务的 IX 锁还没释放,导致该全局锁无法获取。











