临键锁(Next-Key Lock)
简介
在 MySQL 的 InnoDB 存储引擎中,临键锁实际上是两种锁的结合:记录锁和间隙锁。记录锁是在数据行的索引记录上直接加锁,而间隙锁则锁定索引记录之间的间隙。因此,临键锁锁定的是一个索引记录以及该记录之前的间隙。
临键锁通过锁定索引记录以及紧邻索引记录之间的间隙(gap),这样即使是范围查询,也能够确保事务的一致性,防止其他事务对这些范围内的数据进行插入、更新或删除操作。
临键锁用于解决幻读现象,确保事务的隔离级别达到可重复读(REPEATABLE READ)。
临键锁锁定的也是范围,锁定的范围是左开又闭的(a,b]。
原理
临键锁的原理是结合行锁(记录锁)和间隙锁,通过锁定每个索引记录以及前后的间隙,确保在当前事务执行过程中,其他事务不能对这些锁定的范围进行修改,从而避免了幻读现象。
例如,如果一个事务对索引列值为10的记录加了临键锁,它将锁定从上一个索引值到10的间隙以及索引值为10的记录本身。(注意:间隙锁是不会锁定索引值为 10 的)
加锁流程
- 开始事务:启动一个事务。
- 执行范围查询:对特定的索引范围执行查询。
- 加临键锁:InnoDB 在查询范围内的每个索引记录及其前后的间隙上加临键锁。
- 执行操作:在持有临键锁的情况下执行查询或修改操作。
- 释放锁:事务提交或回滚时,释放临键锁。
临键锁的优缺点
优点:
- 数据一致性:临键锁通过锁定数据范围和具体行,保持数据在事务中的一致性,避免了幻读。
- 隔离性强:在可重复读隔离级别下,临键锁提供了非常强的数据隔离保护,使得事务可以在一个一致的数据视图中操作。
缺点:
- 性能影响:临键锁可能会锁定大量的数据范围,导致数据库性能下降,尤其是在处理大量范围查询时。
- 死锁风险:由于锁定了较大的数据范围,临键锁增加了事务之间发生死锁的可能性。
使用场景
临键锁主要在以下场景中使用:
- 范围查询:当执行范围查询时,InnoDB 会在查询范围内的每个索引记录及其前后的间隙上加临键锁。例如,
SELECT * FROM table WHERE id BETWEEN 10 AND 20 FOR UPDATE
。 - 唯一性检查:在插入新记录时,InnoDB 需要检查唯一性约束,可能会在唯一性检查过程中加临键锁,以防止其他事务插入可能导致唯一性冲突的新记录。
示例
假设有一个表 example
,包含以下数据:
CREATE TABLE example (
id INT PRIMARY KEY,
value VARCHAR(50)
);
INSERT INTO example (id, value) VALUES (5, 'A'), (10, 'B'), (15, 'C');
- 事务 A:
START TRANSACTION;
-- 对 id 在 10 到 20 之间的记录及其前后的间隙加临键锁
SELECT * FROM example WHERE id BETWEEN 10 AND 20 FOR UPDATE;
- 事务 B:
START TRANSACTION;
-- 尝试插入 id = 12 的记录,会被阻塞
INSERT INTO example (id, value) VALUES (12, 'D');
在这个示例中:
- 事务 A 对
id
在 10 到 20 之间的记录及其前后的间隙加了临键锁。 - 事务 B 尝试在该范围内插入新的记录
id = 12
,但由于临键锁的存在,事务 B 的插入操作会被阻塞,直到事务 A 提交或回滚。
锁的兼容性矩阵
为了更好地理解锁的兼容性,以下是锁的兼容性矩阵:
锁类型 | IS | IX | S | X |
---|---|---|---|---|
IS | Yes | Yes | Yes | No |
IX | Yes | Yes | No | No |
S | Yes | No | Yes | No |
X | No | No | No | No |
临键锁与其他锁的对比
锁类型 | 锁定粒度 | 作用范围 | 使用场景 | 并发性能 |
---|---|---|---|---|
表锁 | 表级别 | 整个表 | DDL 操作、大批量更新 | 低 |
行锁 | 行级别 | 特定行(索引记录) | 高并发读写 | 高 |
间隙锁 | 行级别(间隙) | 索引记录之间的间隙 | 防止幻读、范围查询、唯一性检查 | 中 |
临键锁 | 行级别(记录+间隙) | 索引记录及其前后的间隙 | 防止幻读、范围查询 | 中 |
插入意向锁 | 行级别 | 索引记录之间的间隙 | 高并发插入 | 高 |
总结
间隙锁是 MySQL InnoDB 存储引擎用于防止幻读现象的一种行级锁,通过锁定索引记录之间的间隙,确保在事务执行过程中数据的一致性。它主要用于范围查询和唯一性检查等场景,通过与行锁和意向锁配合,提供细粒度的并发控制和数据保护机制。在设计高并发系统时,理解和正确使用间隙锁有助于提升系统的性能和可靠性。