mysql自动加is锁或ix锁是在事务对某行加s锁或x锁时,由innodb自动完成:select ... lock in share mode触发is锁,update/delete/insert/select ... for update等触发ix锁。

MySQL什么时候自动加IS或IX锁?
只要事务对某行数据加行级共享锁(S锁)或排他锁(X锁),InnoDB就会**自动**在对应表上加上意向锁——不需要你写任何语句,也不可手动控制。
常见触发场景包括:
-
SELECT ... LOCK IN SHARE MODE或SELECT ... FOR SHARE(加行级S锁 → 表加IS锁) -
UPDATE、DELETE、INSERT ... ON DUPLICATE KEY UPDATE(加行级X锁 → 表加IX锁) -
SELECT ... FOR UPDATE(加行级X锁 → 表加IX锁)
注意:即使SQL只命中一行,只要走的是索引(哪怕唯一索引),InnoDB仍会先加意向锁再加行锁。没走索引?那可能直接升级为表锁,此时也需先获取IX锁(或IS锁)作为前置条件。
为什么LOCK TABLES会受意向锁影响?
当你执行LOCK TABLES user WRITE时,MySQL要确保没人正在操作这张表的任意一行——但不会真的去扫描所有行。它只检查表上有没有IS或IX锁。
如果已有事务持有了IX锁(比如另一个事务刚执行了UPDATE user SET name='x' WHERE id=1),那么LOCK TABLES user WRITE就会被阻塞,直到那个事务提交或回滚。
关键点:
-
IS和IX本身互不冲突(多个事务可同时持有IX) - 但
IS与表级X锁冲突,IX与表级S锁或X锁都冲突 - 所以意向锁不是“锁住数据”,而是“亮红灯”:告诉后来者“这里有人正在动行,你别急着锁整张表”
查不到意向锁,是不是说明没用到?
不能这么判断。意向锁在INFORMATION_SCHEMA.INNODB_TRX和INFORMATION_SCHEMA.INNODB_LOCKS里**默认不显示**(MySQL 8.0+已弃用后者),你几乎看不到它们的身影。
验证方式只有间接观察:
- 执行
SHOW ENGINE INNODB STATUS\G,在TRANSACTIONS部分能看到类似TABLE LOCK table `test`.`user` trx id 12345 lock mode IX的记录 - 用两个session做并发测试:一个
SELECT ... FOR UPDATE,另一个立刻LOCK TABLES ... WRITE——后者卡住,就证明IX锁已生效 - 慢日志里出现
Waiting for table metadata lock不一定和意向锁有关,但Waiting for table level lock往往就是被意向锁拦住了
真正容易被忽略的是:意向锁的存在,让“加表锁”这件事从O(n)降到了O(1),但它本身从不阻塞其他事务加意向锁,也不参与死锁检测——它只是个轻量级信号灯,亮了不代表路封了,但亮了你就得停下来确认下能不能过。











