MySQL意向锁机制
意向锁是一种表级锁,它的核心作用是“声明意图”。 当一个事务想要对表中的某些行加上共享锁或排他锁之前,它会先取得对应表的意向锁。这样,其他事务就能通过查看表级别的意向锁,快速判断表中是否已经被加了行锁,从而避免为了检查冲突而逐行扫描,大大提高了效率。
意向锁有哪些?
MySQL 中的意向锁主要有两种:
意向共享锁(Intention Shared Lock, IS)
- 作用声明:事务打算给表中的某些行设置共享锁(S)。
- 语法:
SELECT ... FOR SHARE
(在 MySQL 8.0+ 中,替代了SELECT ... LOCK IN SHARE MODE
)
意向排他锁(Intention Exclusive Lock, IX)
- 作用声明:事务打算给表中的某些行设置排他锁(X)。
- 语法:
SELECT ... FOR UPDATE
、UPDATE
、DELETE
、INSERT
(对于插入,情况稍特殊,涉及插入意向锁)
注意:意向锁是表级锁,但它们表示的是行级操作的意图。
作用是什么?
意向锁的核心作用是实现多粒度锁机制的和谐共存,具体来说有两个主要目的:
提高效率(冲突检测优化)
如果没有意向锁,当一个事务 A 想给整个表加一个表级写锁(比如LOCK TABLES ... WRITE
)时,它必须去检查表中的每一行是否已经被其他事务加上了行级读锁或写锁。这是一个非常耗时的操作。
有了意向锁之后,事务 A 只需要检查该表是否已经被其他事务加上了意向锁(IS 或 IX)。因为如果另一个事务 B 已经持有某些行的行锁,它必然先持有了表的意向锁(IS 或 IX)。事务 A 发现有意向锁存在,就会直接等待或报错,而无需扫描所有行,极大地提升了性能。表明意图(信号灯机制)
意向锁就像一个信号灯,告诉其他所有事务:“注意,我正在或即将修改这个表中的某些行!”。IS
锁说:“我要读一些行,别给它们加写锁,但可以一起读。”IX
锁说:“我要写一些行,别给它们加读锁或写锁。”
生效的时机是什么?
意向锁的生效和获取时机是自动的、被动的。
获取时机:在你给一行数据加锁之前,InnoDB 存储引擎会自动、隐式地为你先加上对应的意向锁。
- 当你执行
SELECT ... FOR SHARE
时,InnoDB 会:- 自动、隐式地先给表加上一个 IS 锁。
- 然后再给你指定的行加上 S 锁。
- 当你执行
SELECT ... FOR UPDATE
、UPDATE
、DELETE
时,InnoDB 会:- 自动、隐式地先给表加上一个 IX 锁。
- 然后再给你指定的行加上 X 锁。
- 当你执行
释放时机:当事务提交或回滚,释放所有行级锁时,与之关联的意向锁也会被同时释放。
非常重要的一点:你无法手动操作或直接看到意向锁(比如通过 LOCK TABLES ...
语句),它们是 InnoDB 内部为了实现多粒度锁而自动管理的。
锁的兼容性矩阵
理解锁的兼容性是理解其何时生效、何时会阻塞的关键。下表展示了共享锁(S)、排他锁(X)、意向共享锁(IS)、意向排他锁(IX)之间的兼容关系。
当前锁模式 | X | IX | S | IS |
---|---|---|---|---|
X | 冲突 | 冲突 | 冲突 | 冲突 |
IX | 冲突 | 兼容 | 冲突 | 兼容 |
S | 冲突 | 冲突 | 兼容 | 兼容 |
IS | 冲突 | 兼容 | 兼容 | 兼容 |
解读一下这个表:
- 意向锁之间是互相兼容的:IX 和 IS 之间,IX 和 IX 之间,IS 和 IS 之间都是兼容的。因为不同事务可以同时修改同一张表的不同行,这是合理的。
- 表级 S/X 锁和意向锁是冲突的:
- 如果一个事务持有表的 S 锁(表读锁),另一个事务想获取 IX 锁(打算写某些行)是冲突的。因为表读锁不允许任何写操作。
- 如果一个事务持有表的 X 锁(表写锁),另一个事务想获取 IS 或 IX 锁(打算读或写某些行)是冲突的。因为表写锁不允许任何其他操作。
总结
特性 | 说明 |
---|---|
是什么 | 表级锁,表示事务打算对表中的行进行什么类型的操作。 |
类型 | IS(意向共享锁):打算读行。 IX(意向排他锁):打算写行。 |
作用 | 1. 提高效率:避免为加表锁而全表扫描行锁。 2. 声明意图:表明事务的操作意向。 |
生效时机 | 自动、隐式地在添加行级锁(S锁或X锁)之前由 InnoDB 添加。 |
特点 | 意向锁之间是兼容的,但它们与互斥的表级锁不兼容。 |