首页 > 解决方案 > SELECT … FOR UPDATE 对不存在的行

问题描述

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

ID

1

3

8

15

20

列 id 是主键;

当我跑步时:

session1:开始事务;select * from test02 where id = 7 for update;

然后我打开另一个会话,并作为研究员运行:

session2:开始事务;select * from test02 where id = 7 for update;

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

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

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

标签: mysqlselect-for-update

解决方案


MySql 文档(8.0 版):

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

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

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


推荐阅读