意向锁(IS/IX)是InnoDB表级元信息,仅用于声明行锁意图、提升表锁兼容性检查效率,不参与行级并发控制;IS与IX彼此兼容,但均与表级X锁冲突,IX还与表级S锁冲突。

因为意向锁根本不是用来控制行级并发的——它只在表锁申请时被检查,和行锁运行在完全不同的粒度层,两者不参与彼此的兼容性判断。
意向锁和行锁属于不同锁粒度层级
InnoDB 的锁体系是多粒度的:表锁、意向锁、行锁各司其职。意向锁(IS / IX)是表级元信息,仅用于声明“我接下来要对某些行加 S/X 锁”;而行锁(S / X)作用于具体索引记录,负责实际的并发控制。
这意味着:
-
SELECT * FROM t WHERE id = 5 FOR UPDATE会先加IX,再加某行的X锁,但其他事务执行同样语句时,只比对那行的X锁是否冲突,完全不看IX - 两个事务可以同时持有同一张表的
IX,且各自在不同行上加X锁,互不影响 -
SHOW ENGINE INNODB STATUS的LOCK WAIT段里永远不会出现IS或IX—— 它们不构成等待链
意向锁只在表锁申请时才被检查
真正触发阻塞的,永远是表锁与意向锁之间的兼容性规则,而不是意向锁本身在拦路。
例如:
- 事务 A 执行
SELECT ... FOR UPDATE→ 自动加IX(不阻塞任何行操作) - 事务 B 此时执行
LOCK TABLES t WRITE→ 请求表级X锁,发现已有IX,于是等待 - 事务 C 执行
UPDATE t SET a=1 WHERE id=10(走索引)→ 加IX+ 行X锁,完全不受事务 A 的IX影响
注意:事务 B 卡住,不是因为事务 A “占着意向锁不放”,而是因为 InnoDB 在申请表级 X 锁时,按规则必须拒绝与 IX 共存。
没有意向锁时,表锁性能会崩掉
假设删掉意向锁机制,每次 LOCK TABLES t READ 都得扫描全表所有行锁状态来确认是否安全——O(N) 复杂度,在千万级表上可能卡数秒。
有了意向锁后:
-
IS表示“有人准备读部分行”,所以和表级X锁冲突(避免读到不一致快照) -
IX表示“有人准备写部分行”,所以和表级S/X锁都冲突(防止全表读看到部分未提交更新,或全表写破坏行级修改) - 但
IS和IX彼此兼容,多个读/写事务可并行声明意图
这个设计让表锁检查退化为 O(1) 查表级元数据,代价极小,却彻底解耦了表锁决策和行锁执行。
最容易忽略的一点:你写的每条 SELECT ... FOR UPDATE、UPDATE、DELETE 都在悄悄触发 IX,但它从不显式出现在你的 SQL 里,也不参与任何行间竞争——真正复杂的,是你没意识到那个“无关”的 SELECT FOR UPDATE 正在默默影响后续 ALTER TABLE 能否秒级拿到锁。


















