在 MySQL 的 InnoDB 存储引擎中,Gap 锁(间隙锁)是一种用于防止幻读的锁机制。幻读是指在一个事务中,多次执行相同的查询,结果集却不同,通常是由于其他事务插入了新的行。为了防止这种情况,InnoDB 使用 Gap 锁来锁定索引记录之间的间隙,从而阻止其他事务在这些间隙中插入新的行。
Gap 锁的作用
- 防止幻读:通过锁定索引记录之间的间隙,Gap 锁可以防止其他事务在这些间隙中插入新的行,从而避免幻读现象。
- 维护事务隔离性:在某些事务隔离级别下(如
REPEATABLE READ
),Gap 锁帮助确保事务的一致性和隔离性。
Gap 锁的工作原理
- 锁定范围:Gap 锁不仅锁定具体的索引记录,还锁定索引记录之间的间隙。例如,如果索引中有值 10 和 20,那么 Gap 锁会锁定 (10, 20) 之间的间隙。
- 锁定方式:Gap 锁是共享的,这意味着多个事务可以在同一间隙上持有 Gap 锁。但是,如果有事务在某个间隙上持有 Gap 锁,其他事务就不能在这个间隙中插入新的记录。
示例
假设有一个表 orders
,其结构如下:
Sql
CREATE TABLE orders (id INT PRIMARY KEY,order_number INT
);
并且表中已经存在以下数据:
id | order_number |
---|---|
1 | 10 |
2 | 20 |
情景 1: 查询并锁定
假设一个事务执行以下查询:
Sql
SELECT * FROM orders WHERE order_number = 15 FOR UPDATE;
由于 order_number = 15
的记录不存在,InnoDB 会在 order_number
索引上的 (10, 20) 间隙上放置一个 Gap 锁。这防止了其他事务在 (10, 20) 之间插入新的记录。
情景 2: 插入操作
假设另一个事务尝试插入一个新的记录:
Sql
INSERT INTO orders (id, order_number) VALUES (3, 15);
由于第一个事务已经在 (10, 20) 间隙上放置了 Gap 锁,第二个事务将被阻塞,直到第一个事务提交或回滚。
Gap 锁和 Next-Key 锁
- Next-Key 锁:Next-Key 锁是 Gap 锁和 Record 锁的组合。它不仅锁定索引记录本身(Record 锁),还锁定索引记录之间的间隙(Gap 锁)。这样可以同时防止幻读和不可重复读。
- 默认行为:在
REPEATABLE READ
隔离级别下,InnoDB 默认使用 Next-Key 锁来防止幻读。
如何查看 Gap 锁
你可以通过 Performance Schema 来查看当前的锁情况。例如,查询 performance_schema.data_locks
表可以显示当前活跃的锁信息。
Sq
SELECT * FROM performance_schema.data_locks WHERE LOCK_TYPE = 'RECORD' AND LOCK_MODE = 'GAP';
这个查询会显示当前系统中所有的 Gap 锁。
总结
Gap 锁是 InnoDB 用来防止幻读的一种锁机制。它锁定索引记录之间的间隙,从而阻止其他事务在这些间隙中插入新的行。通过这种方式,InnoDB 能够在 REPEATABLE READ
隔离级别下提供更高的事务一致性。理解 Gap 锁对于优化并发性能和解决锁冲突问题非常重要。