意向锁(is/ix)是innodb自动加的表级轻量标记,用于避免表锁检查时逐行扫描行锁,大幅提升冲突检测效率;is由select lock in share mode触发,ix由insert/update/delete/select for update触发,二者互不阻塞但均与表级x锁冲突。

表锁检查不扫行,只看意向锁标记
因为逐行检查行锁是否冲突太慢。一张千万行的表,LOCK TABLES t WRITE如果真去遍历每一行判断有没有 SELECT FOR UPDATE 或 UPDATE 正在持有的 X 锁,光检测就可能卡住几秒——意向锁就是为绕过这一步而生的。
IS/IX 是 InnoDB 自动在表级别加的轻量标记,不锁数据、不阻塞行操作,只表达“我接下来要对某些行加 S/X 锁”的意图。其他事务申请表锁时,只需查表上有没有冲突的意向锁,就能立刻决定是成功还是等待。
- 有
IX锁 → 拒绝LOCK TABLES t WRITE和LOCK TABLES t READ - 有
IS锁 → 允许LOCK TABLES t READ,但拒绝LOCK TABLES t WRITE -
IS和IX并存 → 完全允许,互不阻塞(这是高并发能成立的前提)
哪些语句会触发 IS 或 IX 锁?
你写 SQL 时不显式加,InnoDB 在执行前自动加;但必须清楚谁带出什么锁,否则查不出阻塞根源。
-
SELECT ... LOCK IN SHARE MODE→ 触发IS锁(同时对命中行加 S 锁) -
SELECT ... FOR UPDATE、INSERT、UPDATE、DELETE→ 触发IX锁(同时对命中行加 X 锁) - 没走索引的 DML(如
UPDATE t SET a=1 WHERE b='x'且b无索引)→ 仍加IX,但会对全表每行加 X 行锁,效果接近“伪表锁”
注意:IX 锁长期存在 ≠ 意向锁本身有问题,大概率是背后事务没提交、SQL 执行慢、或锁了不该锁的范围。
为什么 IS 和 IX 彼此兼容,却都和表级 X 锁冲突?
意向锁本质是“声明”,不是“占有”。IS 说“我打算读几行”,IX 说“我打算改几行”,它们不矛盾,所以可以共存;但表级 X 锁意味着“整张表归我独占”,和任何“有人想动里面某几行”的声明天然冲突。
这个设计让多粒度锁真正可行:行锁可并发,表锁可快速判定是否安全,二者不打架。
- 兼容性判断只发生在“意向锁 vs 表锁”之间,不是“意向锁 vs 行锁”
-
IS和IX都不阻塞行级S/X锁,只影响更高层的表锁请求 - 监控时单看
performance_schema.data_locks中的IS/IX记录没用,得结合INFORMATION_SCHEMA.INNODB_TRX看事务状态,否则容易把网络超时或应用层未COMMIT误判成锁问题
ALTER TABLE 卡住?先查 IX 锁是否残留
线上 ALTER TABLE 长时间卡住,90% 是因为有未提交事务正持有 IX 锁,导致 DDL 拿不到表级排他锁。
- MySQL 5.7 默认关闭
performance_schema,需启动时加--performance-schema=ON - MySQL 8.0+ 默认开启,但查
data_locks表需要PROCESS权限 - 执行
SELECT object_schema,object_name,lock_type,lock_mode FROM performance_schema.data_locks WHERE lock_type = 'TABLE',重点看lock_mode是否为IX,再关联INNODB_TRX找出对应事务
真正难处理的不是意向锁本身,而是它背后暴露的事务生命周期问题:长事务、慢查询、没索引的 DML、应用层忘记 COMMIT —— 这些才是实际要盯死的地方。











