首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >MySQL间隙锁定行为与预期不符

MySQL间隙锁定行为与预期不符
EN

Stack Overflow用户
提问于 2020-12-11 12:18:52
回答 1查看 174关注 0票数 0

问题描述:

在MySQL8.0中,我启动了一个事务并执行了一个事务(transaction one),然后启动了另一个事务并执行了id = 101 (transaction 2),并且 child,中有一行,但是这个事务2被阻塞了。

如果我执行update child set id = id+10 where id = 102;(事务3),并且表中不存在行id = 102,事务3将不会被阻塞,并且可以成功地执行。

就我而言,MySQL8.0 gap锁只锁定id大于1000的行,但在第二个事务中,行id为101,而不大于1000,因此这两个事务不会相互冲突。那么,为什么事务二被事务一阻塞呢?

详细信息如下:

  1. child结构:

CREATE TABLE `child` (\n `id` int NOT NULL,\n PRIMARY KEY (`id`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci

  1. child中的所有数据
代码语言:javascript
运行
复制
mysql root@localhost:test> select * from child;
+------+
| id   |
+------+
| 90   |
| 101  |
| 105  |
| 106  |
| 109  |
| 111  |
| 1007 |
+------+
7 rows in set
  1. 所有MySQL8.0配置都是默认的。
  2. 这两个事务是并行的。
EN

回答 1

Stack Overflow用户

发布于 2020-12-16 11:59:39

简化一点,锁定将始终附加到现有的对象,例如行。

假设您的表中有in 90、101、105、106、109、110和1007。请注意,我将您的示例行111更改为110,否则,更新从101到111将因主键违规而失败,然后才会遇到锁问题。

如果MySQL需要为WHERE id > 1000发出一个锁,它将不会(因为它不能)跟踪确切的值> 1000。相反,它将接受与该值最近的现有对象(在您的示例中是id 110的行),并添加一个间隙锁,该锁覆盖从110到1006的空间。和另一个锁+间隙锁,在行与id 1007,涵盖空间从1007和更高。

是的,这涵盖了比需要更多的空间。但是这个锁包含了所需要的空间,这是重要的方面。

您的update child set id = id+10 where id = 101现在将将行移动到锁定的空间中,因此必须等待现有锁的释放。因此,这实际上是预期的行为,因为MySQL是如何工作的。

如果在112到1000之间还有另一行,则可以从那里开始间隙锁,并且您的更新事务无需等待。

实际上,这是一个问题,特别是对于小表(或特定的更新/插入-模式)。如果添加了越来越多的行,随机更新击中“覆盖过大”的漏洞的可能性就会降低。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65251249

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档