意向锁
你的疑惑很自然:“锁就锁好了,怎么还要个‘意向’?” 问题的关键在于,InnoDB 里存在两种粒度完全不同的锁:行锁(细粒度)和表锁(粗粒度)。意向锁就是用来沟通这两种锁的“信使”。
核心问题:没有意向锁会怎样?
假设没有意向锁。事务 A 正在修改某一行(加了行锁)。此时事务 B 想对整个表加表锁(比如 LOCK TABLES t WRITE 做 DDL)。为了判断表能否加锁,数据库必须逐行检查表中是否有行锁——这意味着要遍历整个表,效率极低,并发性也差。
意向锁的作用:快速判断“表里是否已有行锁”
- 意向锁是一种表级锁,但它不锁定行数据,只表达一个“意向”。
- 在一个事务获得某行的行锁之前,它必须先获得该行所在表的意向锁(意向共享锁 IS 或意向排他锁 IX)。
- 当另一个事务想加表锁时,只需要检查表上是否存在冲突的意向锁,就能快速知道“表里是否已经有人锁了某些行”,而不需要遍历所有行。
为什么叫“意向”?
因为事务打算(intend)去加行锁,所以先在表级别留下一个“意向”标记。这就像你要进房间拿东西,先敲个门说“我要进来”(意向),而不是直接闯进去。
意向锁的兼容性(关键规则)
| 锁类型 | 意向共享锁 (IS) | 意向排他锁 (IX) | 共享表锁 (S) | 排他表锁 (X) |
|---|---|---|---|---|
| IS | 兼容 | 兼容 | 兼容 | 冲突 |
| IX | 兼容 | 兼容 | 冲突 | 冲突 |
| S | 兼容 | 冲突 | 兼容 | 冲突 |
| X | 冲突 | 冲突 | 冲突 | 冲突 |
- 表锁 S:不允许任何事务修改行(因为会加 IX 或 X),但允许读行(IS 兼容)。
- 表锁 X:不允许任何事务读写行(IS/IX 都冲突)。
这张表不是“已经有的锁列表”,而是锁兼容性矩阵,表示:
- 当某个事务已经持有某种表锁时,
- 另一个事务再来申请另一种锁,
- 两者是“兼容”(可同时存在)还是“冲突”(需要等待)。
你圈的 IS/IX/S/X 是 InnoDB 的表级意向锁/表锁类型:
IS:意向共享锁(表示“我准备在行上加 S 锁”)IX:意向排他锁(表示“我准备在行上加 X 锁”)S:共享表锁X:排他表锁
比如表中 IX 和 S 是冲突,意思是:如果一个事务持有 IX,另一个事务想加 S 表锁就要等;IS 和 IX 兼容则可以并存。
所以结论:这是规则表,不是当前数据库里“已经加了哪些锁”的实时状态。
实际例子
-- 事务 A
BEGIN;
SELECT * FROM user WHERE id = 1 FOR UPDATE; -- 先自动给 user 表加 IX 锁,再给 id=1 这行加 X 锁
-- 事务 B
LOCK TABLES user WRITE; -- 想加 X 表锁,发现表上已有 IX 锁(冲突),立即阻塞,不需要扫描行锁。
一句话总结
意向锁是为了让表锁能高效地判断“表里有没有行锁”而引入的轻量级表级锁。“意向”就是“我打算要锁行”的意思,它只是打个招呼,并不实际锁住数据。 没有它,数据库就得全表扫描去检查行锁,那代价就太大了。