mysql - 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 都显示相同的结果。
解决方案
从MySql 文档(8.0 版):
这里还值得注意的是,不同的事务可以在间隙上持有冲突的锁。例如,事务 A 可以在一个间隙上持有一个共享间隙锁(gap S-lock),而事务 B 在同一个间隙上持有一个排他性间隙锁(gap X-lock)。允许冲突间隙锁的原因是,如果从索引中清除记录,则必须合并不同事务在记录上持有的间隙锁。
InnoDB 中的间隙锁是“纯粹的抑制性”,这意味着它们的唯一目的是防止其他事务插入到间隙中。间隙锁可以共存。一个事务采用的间隙锁不会阻止另一个事务在同一间隙上采用间隙锁。共享和独占间隙锁之间没有区别。它们彼此不冲突,并且执行相同的功能。
在您的示例中,会话 2 不会等待会话 1,因为这正是 MySQL 中间隙锁的工作方式。否则就是期望与产品文档相矛盾的行为。
推荐阅读
- javascript - 从用户那里收集二进制数并在 JavaScript 中将其转换为十进制
- flutter - 无法在flutter webview中返回上一页
- amazon-web-services - 如何使用 AWS CLI 访问和复制 Cloudian S3 文件
- python - 名称“项目”未定义
- stripe-payments - 条纹测试卡,用于允许未捕获但未通过“真实”捕获的费用
- go - Golang - 创建一个与传递的相同类型的对象
- python-3.x - 为什么在使用 buildozer 调试后出现“命令失败”错误?
- r - 用另一个列表改变数据框列表
- haskell - 如何使用镜头“重新排列”Aeson.Object?
- dataframe - Julia 数据框直接访问行