外观
间隙锁在哪个隔离级别?
⭐ 题目日期:
腾讯 - 2024/08/19
📝 题解:
间隙锁(Gap Lock)主要用于 可重复读(Repeatable Read) 隔离级别,是 MySQL InnoDB 引擎防止幻读(Phantom Read)的核心机制之一。以下是详细说明:
1. 间隙锁的作用
- 锁定范围:间隙锁锁定的是索引记录之间的“间隙”(即两个索引值之间的区间),而非具体的数据行。
- 防止幻读:通过锁定可能插入新数据的范围,阻止其他事务在间隙内插入新记录,从而避免事务内多次查询结果集的行数变化。
示例: 假设表中有索引值 10, 20, 30
,事务 A 查询 WHERE id > 15
:
- 间隙锁会锁定区间
(10, 20)
和(20, 30)
,阻止其他事务插入15
、25
等值。
2. 隔离级别与间隙锁的关系
3. Next-Key Lock:间隙锁的增强版
- 定义:Next-Key Lock = 行锁(Record Lock) + 间隙锁(Gap Lock),锁定索引记录及其前面的间隙。
- 作用:在可重复读级别下,既防止其他事务修改当前行,又阻止在范围内插入新数据。
- 示例: 若事务 A 执行
SELECT * FROM table WHERE id = 20 FOR UPDATE
:- 锁定索引值
20
(行锁)。 - 锁定其前一个间隙
(10, 20)
(间隙锁)。 - 其他事务无法插入
id=15
或修改id=20
。
- 锁定索引值
4. 如何验证间隙锁的存在?
- 场景模拟:
事务 A 执行范围查询并加锁:
BEGIN; SELECT * FROM user WHERE age BETWEEN 20 AND 30 FOR UPDATE;
事务 B 尝试在间隙内插入数据:
INSERT INTO user (id, age) VALUES (5, 25); -- 阻塞,直到事务 A 提交或超时
结果:事务 B 被阻塞,证明间隙锁生效。
5. 注意事项
- 仅针对非唯一索引:若查询条件使用唯一索引且精确匹配(如
WHERE id = 20
),InnoDB 可能退化为行锁,无需间隙锁。 - 显式禁用间隙锁:
- 设置隔离级别为 读已提交(Read Committed)。
- 设置
innodb_locks_unsafe_for_binlog = 1
(但此参数在 MySQL 8.0 中已废弃)。
- 性能影响:间隙锁会增加锁冲突概率,高并发写入场景可能引发死锁或性能下降。
总结
- 间隙锁仅在可重复读(Repeatable Read)隔离级别下默认启用,是 InnoDB 防止幻读的核心机制。
- 若需避免间隙锁的副作用(如减少锁冲突),可降级至 读已提交(Read Committed),但需容忍幻读风险。
- 合理设计索引(如尽量使用唯一索引)能减少间隙锁的锁定范围,优化并发性能。