当前没有IS/IX锁直接阻塞,真正阻塞源于表级显式锁或DDL与IS/IX的兼容性冲突;需通过SHOW ENGINE INNODB STATUS查看等待事务及持有事务,结合information_schema.INNODB_TRX和performance_schema.data_locks定位根因。

怎么看当前有没有IS/IX锁在阻塞
意向锁本身不直接阻塞其他事务,真正造成阻塞的是「表级显式锁」(LOCK TABLES ... READ/WRITE)或DDL操作(如ALTER TABLE)与IS/IX的兼容性冲突。排查第一步不是查IS/IX本身,而是查谁在等、等什么。
执行SHOW ENGINE INNODB STATUS\G,重点看TRANSACTIONS和LATEST DETECTED DEADLOCK两节:
-
TRANSACTIONS里找lock wait字样,确认等待线程ID和它想申请的锁类型(比如TABLE LOCK table `test4` trx id 12345 lock mode IX waiting) - 再往上翻,找到持有锁的事务,看它是否持有了
IS或IX(通常不会单独列出,但可通过它正在执行的SQL反推:比如SELECT ... LOCK IN SHARE MODE→ 必有IS;UPDATE或SELECT ... FOR UPDATE→ 必有IX) - 如果等待方是
LOCK TABLES test4 WRITE或ALTER TABLE test4 ADD COLUMN,而持有方有IX,那就是典型冲突:IX与表X锁互斥
为什么SELECT ... FOR UPDATE会卡住ALTER TABLE
这不是FOR UPDATE本身的问题,而是它触发了IX意向排他锁,而ALTER TABLE需要先获得表级X锁——IX与X不兼容,所以ALTER被挂起。
-
IX表示“我正在/即将对这表某些行加X锁”,ALTER必须确保整张表没人在动数据,所以它必须等所有IX释放 - 常见陷阱:长事务里执行了
SELECT ... FOR UPDATE但没提交,导致后续所有ALTER、OPTIMIZE TABLE、LOCK TABLES ... WRITE全部排队 - 验证方法:在另一个session执行
SELECT * FROM information_schema.INNODB_TRX WHERE TRX_STATE = 'LOCK WAIT',关联INNODB_LOCK_WAITS看等待链
IS锁和IX锁之间从不冲突
这是最容易误解的一点:很多人看到两个事务都执行SELECT ... LOCK IN SHARE MODE,就以为它们的IS锁会互相阻塞——不会。IS与IS、IS与IX、IX与IX全部兼容。
- 真正冲突的组合只有:
ISvsX表锁、IXvsS表锁、IXvsX表锁 - 所以如果你观察到两个
SELECT ... FOR UPDATE语句互相等待,问题一定不在IX上,而在行锁本身(比如锁了同一行、死锁、或WHERE没走索引导致锁全表) - 用
SELECT * FROM performance_schema.data_locks可查具体锁对象(注意:MySQL 8.0+才默认启用该表,且需开启performance_schema)
别试图手动加IS或IX锁
没有语法支持。你搜到的LOCK TABLES t IS或SELECT ... FOR IS全是错的——InnoDB不提供任何用户控制意向锁的接口。
- 意向锁由InnoDB在加行锁前自动申请,事务结束时自动释放
- 试图绕过机制(比如用
LOCK TABLES ... READ代替行锁)反而会放大阻塞面:S表锁会阻塞所有IX,包括其他业务的UPDATE - 真正要优化的,是减少长事务、确保WHERE条件命中索引(避免全表扫描触发大量行X锁,间接让
IX长期持有)
最常被忽略的点:意向锁冲突从来不是孤立事件,它只是表级操作受阻的“症状”。盯住谁在等X锁、谁持有IX、这个IX对应的实际行锁是否必要且及时释放——这才是根因。


















