意向锁由innodb自动管理,不可手动加;事务对行加s/x锁时自动在表上加is/ix,用于阻塞冲突的表级锁而非行锁,其有效前提为sql走索引。

意向锁不是手动加的,别写 LOCK TABLE ... IN IS MODE
MySQL 的 IS(意向共享锁)和 IX(意向排他锁)由 InnoDB 自动管理,你无法也不应该手动申请。所有试图用 SQL 显式加意向锁的操作都会报错或被忽略——比如 LOCK TABLE t READ 加的是表级读锁,不是 IS;SELECT ... LOCK IN SHARE MODE 会触发 IS,但这是隐式过程。
常见错误现象:
- 执行
SELECT ... FOR UPDATE后查performance_schema.data_locks,发现有IX锁,误以为是自己“加上去的” - 在事务中先
SELECT ... LOCK IN SHARE MODE,再UPDATE,结果看到IS和X行锁共存,以为要“配合使用意向锁”
真实逻辑是:只要事务准备对某行加 S 锁,InnoDB 就自动在表上加 IS;加 X 锁前,自动加 IX。你只管写业务 SQL,引擎替你铺路。
IS 和 IX 之间完全兼容,但会阻塞表级 S/X 锁
意向锁本身不互斥:IS 与 IX 可以同时存在一张表上,多个事务也能并行持有它们。真正起作用的是它们对**表级锁**的拦截能力。
关键兼容规则:
- 当表上有
IS或IX时,LOCK TABLE t READ(表级读锁)会被阻塞——因为读锁要求整张表没任何行被加锁,而IS/IX表明“已有行锁意图”,必须等 - 当表上有
IX时,LOCK TABLE t WRITE(表级写锁)也会被阻塞——写锁要求绝对独占,连“想加行锁”的意图都不允许 - 但
IS不影响其他事务加IX,IX也不阻止其他事务加IS
所以意向锁本质是“信号灯”:不拦行锁,只拦表锁。它让表锁检查从遍历千万行降为一次元数据判断。
查意向锁只能看 performance_schema.data_locks,且需注意字段含义
想确认当前有没有 IS 或 IX,唯一可靠方式是查 performance_schema.data_locks 视图:
SELECT OBJECT_SCHEMA, OBJECT_NAME, INDEX_NAME, LOCK_TYPE, LOCK_MODE, LOCK_DATA FROM performance_schema.data_locks WHERE LOCK_TYPE = 'TABLE';
注意三点:
-
LOCK_TYPE = 'TABLE'才是表级锁,其中LOCK_MODE显示IS或IX -
LOCK_MODE字段值是字符串,如'IS'、'IX'、'S'(表级共享锁)、'X'(表级排他锁),别和行锁的S/X混淆 - 该视图只显示当前活跃事务持有的锁,事务提交后记录立即消失;且需提前开启
performance_schema并启用相关 instruments
意向锁失效的典型场景:没走索引导致升级为表锁
意向锁只有在行锁生效时才有意义。如果 SELECT ... FOR UPDATE 没命中索引,InnoDB 会退化为锁全表——此时加的不是 IX + 多个行 X,而是直接加一个表级 X 锁。
后果很直接:
- 后续所有对该表的
SELECT ... LOCK IN SHARE MODE都会被阻塞,不是因为IS冲突,而是因为表X锁本身排斥一切其他锁 -
performance_schema.data_locks里看到的是LOCK_TYPE = 'TABLE'且LOCK_MODE = 'X',没有IX记录 - 你以为的“意向锁协调”根本没启动,锁粒度已经崩了
所以真正要盯住的,从来不是怎么“用好意向锁”,而是确保你的 FOR UPDATE 和 LOCK IN SHARE MODE 一定走索引——这是意向锁发挥价值的前提。











