SELECT … FOR UPDATE 对不存在的行

Posted

技术标签:

【中文标题】SELECT … FOR UPDATE 对不存在的行【英文标题】:SELECT … FOR UPDATE on non-existent rows 【发布时间】:2020-07-15 04:13:14 【问题描述】:

当“选择...更新不存在的行”时,我对锁感兴趣; 目前,'test02'表中的数据如下:

身份证

1

3

8

15

20

列id为主键;

当我跑步时:

会话 1: 开始交易; select * from test02 where id = 7 for update;

然后我打开另一个会话,并作为伙伴运行:

会话2: 开始交易; select * from test02 where id = 7 for update;

正如我所料,session2 将等待间隙锁 (3, 8);但是两个会话正常运行。有没有人可以帮助解释为什么 session2 不等待?

但是当我在 session3 中运行以下 sql 时:插入 test02(id) 值 (7);会话被阻塞,这意味着使用了 session1 中的间隙锁。但是我不明白为什么session2可以正常运行。

mysql 5.7 和 5.8 都显示相同的结果。

【问题讨论】:

但是当我在 session3 中运行以下 sql 时:插入 test02(id) 值 (7);会话被阻塞,这意味着使用了 session1 中的间隙锁。但我不明白 session2 在哪里可以正常运行。 请编辑您的问题以包含您在上面的评论。该评论与问题本身相关,可能会被前来回答的人忽略。 【参考方案1】:

来自MySql documentation(8.0版):

这里还值得注意的是,冲突锁可以在一个 不同交易的差距。例如,交易 A 可以持有 当事务 B 持有一个间隙时,在间隙上共享间隙锁(间隙 S 锁) 同一个间隙上的排他间隙锁(gap X-lock)。原因 允许冲突的间隙锁是,如果一条记录被清除 一个索引,不同事务在记录上持有的间隙锁 必须合并。

InnoDB 中的间隙锁是“纯粹的抑制性”,这意味着它们的 唯一的目的是防止其他事务插入到 差距。间隙锁可以共存。一个事务采取的间隙锁确实 不阻止另一个事务对同一个事务进行间隙锁 差距。共享和独占间隙锁之间没有区别。 它们彼此不冲突,并且执行相同 功能。

在您的示例中,会话 2 不会等待会话 1,因为这正是 MySQL 中间隙锁的工作方式。否则就是期望与产品文档相矛盾的行为。

【讨论】:

以上是关于SELECT … FOR UPDATE 对不存在的行的主要内容,如果未能解决你的问题,请参考以下文章

当行不存在时,“SELECT FOR UPDATE”是不是会阻止其他连接插入?

由SELECT ... FROM ... FOR UPDATE想到的

数据库中Select For update语句的解析

MySQL的SELECT.FOR UPDATE究竟起啥作用

MySQL的SELECT ...for update

MySQL的SELECT ...for update