Mysql

关注公众号 jb51net

关闭
首页 > 数据库 > Mysql > mysql行锁和间隙锁

MySQL 中的行锁(Record Lock) 和 间隙锁(Gap Lock)详解

作者:大G的笔记本

InnoDB中的行锁(RecordLock)和间隙锁(GapLock)是用于保证事务隔离性的两种锁机制,本文给大家介绍MySQL中的行锁(Record Lock) 和间隙锁(Gap Lock),感兴趣的朋友跟随小编一起看看吧

1. 行锁(Record Lock)

定义

作用

触发场景

例子

假设有表:

CREATE TABLE user ( id INT PRIMARY KEY, name VARCHAR(50), age INT ) ENGINE=InnoDB;

事务 A:

BEGIN; SELECT * FROM user WHERE id=5 FOR UPDATE;
UPDATE user SET age=30 WHERE id=5;

会被阻塞,直到事务 A 提交或回滚。

2. 间隙锁(Gap Lock)

定义

作用

触发场景

例子

假设表中有数据:

id: 1, 5, 10

事务 A:

BEGIN; SELECT * FROM user WHERE id BETWEEN 5 AND 10 FOR UPDATE;
INSERT INTO user VALUES (7, 'Tom', 25);

会被阻塞,因为 (5,10) 的间隙被锁住。

3. 区别总结

锁类型锁住对象作用常见场景
Record Lock某一行的索引记录防止该行被修改或删除精确匹配索引的 UPDATEDELETESELECT ... FOR UPDATE
Gap Lock索引记录之间的空隙防止在范围内插入新记录范围查询加锁,防止幻读

总结

BEGIN;
SELECT * FROM user WHERE id BETWEEN a AND b FOR UPDATE;

如果a和b距离很大是否直接锁住a和b中间所有行

是的,

在 InnoDB 的 REPEATABLE READ 隔离级别下,执行

BEGIN; SELECT * FROM user WHERE id BETWEEN a AND b FOR UPDATE;

会触发 Next-Key LockRecord Lock + Gap Lock 的组合),它会锁住范围内所有匹配的行,并且锁住这些行之间的间隙,防止其他事务在这个范围内插入新数据。

1. 锁定范围的规则

假设 id 是主键索引,表中数据如下:

id: 1, 5, 10, 20, 50, 100

如果执行:

SELECT * FROM user WHERE id BETWEEN 5 AND 50 FOR UPDATE;

InnoDB 会:

2. 如果 a 和 b 很远

如果 a=5b=1000000,而表中有很多行:

3. 注意事项

4. 直观示意

假设:

id: 1, 5, 10, 20, 50, 100

执行:

SELECT * FROM user WHERE id BETWEEN 5 AND 50 FOR UPDATE;

锁定范围:

[5]====(gap)====[10]====(gap)====[20]====(gap)====[50]====(gap)====

我建议,如果你的 ab 之间范围特别大,可以考虑:

为什么5前面没有被锁住?

在执行

BEGIN; SELECT * FROM user WHERE id BETWEEN 5 AND 50 FOR UPDATE;

的时候,为什么 id=5 前面的间隙(比如 (1,5))没有被锁住?

核心原因:锁定范围是由查询条件决定的

InnoDB 的 Next-Key Lock(行锁 + 间隙锁)只会锁住满足查询条件的记录以及这些记录之间的间隙。

锁定范围的精确规则

REPEATABLE READ 隔离级别下:

  1. Record Lock:锁住满足条件的记录(这里是 id=5, 10, 20, 50)。
  2. Gap Lock:锁住这些记录之间的间隙,以及最后一条记录到下一条记录之间的间隙。
  3. 不锁条件范围外的间隙,因为它们不会导致幻读。

例子对比

假设表数据:

id: 1, 5, 10, 20, 50, 100

查询:

SELECT * FROM user WHERE id BETWEEN 5 AND 50 FOR UPDATE;

锁定范围:

[5]====(gap)====[10]====(gap)====[20]====(gap)====[50]====(gap)====

如果是:

SELECT * FROM user WHERE id >= 5 FOR UPDATE;

锁定范围:

[5]====(gap)====[10]====(gap)====[20]====(gap)====[50]====(gap)====[100]====(gap)====

如果是:

SELECT * FROM user WHERE id > 1 FOR UPDATE;

锁定范围:

(1,5)====[5]====(gap)====[10]====(gap)====[20]====(gap)====[50]====(gap)====[100]====(gap)====

总结

到此这篇关于MySQL 中的行锁(Record Lock) 和 间隙锁(Gap Lock)详解的文章就介绍到这了,更多相关mysql行锁和间隙锁内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文