is和ix锁是innodb自动加的表级意向锁,用于预告事务将对某些行加s锁或x锁,本身不阻塞行读写,但会与表级锁(如lock tables write)冲突,且无法手动加锁。

IS 和 IX 锁是 InnoDB 自动加的表级“预告锁”
IS(Intention Shared)和 IX(Intention Exclusive)不是你能写 SQL 主动申请的锁,LOCK TABLES t READ 或 LOCK TABLES t WRITE 会触发冲突检测,但你永远写不出 SELECT ... LOCK IN SHARE MODE 以外的语句去“加 IS 锁”——InnoDB 在执行那条语句时,内部自动加上 IS;同理,SELECT ... FOR UPDATE、UPDATE、DELETE 触发 IX。
它们不锁数据,只在表级别打个标记:“我接下来要对某些行加 S 锁(IS)”或“我接下来要对某些行加 X 锁(IX)”。这个标记让后续想加整表锁的事务能快速判断:表里是否已有行被锁定。
- 你无法用
SELECT ... LOCK IN SHARE MODE之外的方式触发 IS 锁 -
INSERT虽不显式加锁,但在唯一键冲突或外键检查时也可能触发 IX - 事务未提交前,IS/IX 一直持有;rollback 或 commit 后才释放
IS/IX 之间完全兼容,但会阻塞某些表锁
意向锁设计初衷就是“不互斥”,多个事务可以同时持有同一张表的 IS 和 IX——因为它们只是预告,不代表实际冲突。真正起阻塞作用的是它和显式表锁(LOCK TABLES)之间的兼容性规则:
-
IS兼容LOCK TABLES ... READ(S 表锁),但不兼容LOCK TABLES ... WRITE(X 表锁) -
IX和两种表锁都不兼容:既不能和 S 表锁共存,也不能和 X 表锁共存 - 普通 DML(如无锁
SELECT、带索引的UPDATE)完全不受 IS/IX 影响,它们只和行锁打交道
换句话说:IS/IX 不影响并发读写行,只影响你能不能对整张表上 LOCK TABLES。
为什么不能手动加 IS 或 IX 锁?
MySQL 语法根本不支持。你试一下 LOCK TABLES t INTENTION SHARE 或任何带 INTENTION 的语句,会直接报错 ERROR 1064。这是因为意向锁是存储引擎层的协调机制,不是用户接口层的控制手段。
- 试图搜索 “MySQL 手动加 IS 锁” 是无效方向,所有相关文档或 Stack Overflow 提问都指向误解
-
SHOW ENGINE INNODB STATUS中能看到IS、IX状态,但那是观察结果,不是操作入口 - 如果你在监控中看到大量
IS锁等待,问题大概率出在有人频繁执行LOCK TABLES ... WRITE,而不是你的业务 SQL 写错了
常见误判场景:把 IS/IX 当成性能瓶颈
很多同学看到慢查询日志里出现 “waiting for table metadata lock”,或 SHOW PROCESSLIST 显示状态为 Waiting for table level lock,就怀疑是 IS/IX 导致阻塞——其实几乎不可能。真正卡住的通常是:
- 长事务没提交,导致其持有的 IS/IX 持续存在,而另一个会话正尝试
LOCK TABLES ... WRITE - DDL 操作(如
ALTER TABLE)需要 X 表锁,被前面的 IX 锁挡住 - 误用
FLUSH TABLES WITH READ LOCK后忘记释放,整个表锁死
IS/IX 本身极轻量,不会造成明显延迟;但一旦它们成为表锁请求的“拦路虎”,说明系统里混进了本不该长期持有的表级操作——这才是该盯住的地方。











