我有以下问题,我想用图表来确认我的理解是否正确:

SELECT * FROM table WHERE pk > 99;

PK为主键

enter image description here

我很难理解下一把 keys 锁,我找到了这张图,以了解哪个间隙锁将被应用,以及哪一把"下一把 keys 锁".

If the diagram is WRONG, let me know.

推荐答案

这张图看起来很正确.

我假设您的示例中的pk是InnoDB表的主键,因此是聚集索引.

间隙从大于97的一个值开始锁定,并一直延伸到无穷大.

这似乎很奇怪,因为值98和99看起来应该没有锁,因为条件为WHERE pk > 99,因此与值98或99不匹配.但是Next-key锁锁定索引记录之前的whole gap,直到但不包括前面的索引记录.

https://dev.mysql.com/doc/refman/8.0/en/innodb-locking.html#innodb-next-key-locks表示:

索引记录上的Next-key锁也会影响该索引记录之前的"间隙".也就是说,Next-key锁是索引记录锁加上索引记录前面的间隙上的间隙锁.

演示:在第一个窗口中,我启动了一个获取Next-key锁的事务:

mysql> select * from mytable;
+-----+-------+
| pk  | name  |
+-----+-------+
|   3 | hello |
|  97 | hi    |
| 101 | hola  |
| 103 | yo    |
| 107 | hey   |
+-----+-------+

mysql> start transaction;

mysql> select * from mytable where pk > 99 for update;
+-----+------+
| pk  | name |
+-----+------+
| 101 | hola |
| 103 | yo   |
| 107 | hey  |
+-----+------+

现在锁定了PK 101的索引记录,以及PK 97之后的差距.

在第二个窗口中,我测试了以下内容:

mysql> insert into mytable values (99, 'test');
(hangs)

mysql> insert into mytable values (98, 'test');
(hangs)

mysql> update mytable set name='test' where pk=97;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

Mysql相关问答推荐

是否有一种方法可以在mysql中设置一列,使其自动成为该行的行号的值?

SQL:CAST与窗口函数组合导致语法错误

如何从MySQL数据库中提取入职第一个月的工作天数?

为什么 MAX 函数通过调用在 group 中生成正确的结果

Mysql,从两个不同的表中添加原始数据,从第一个表中获取所有内容,仅从第二个表中获取curdate内容

GoRM中行最大值查询返回"0"

global max_connections 和 spring.hikari.maximumPoolSize 有什么区别?

MySQL,递归 CTE.它如何以这种句法形式工作?

错误1075:表定义不正确;只能有一个自动列,它必须定义为一个键(使用 gorm 和 mysql)

MySQL 使用了错误的索引

此更新查询是否有任何可能的重写选项?

如何在更新语句中使用多个子字符串函数?

在 SQL 中 for each 组返回具有最大值的行,包括具有相同值的行

MYSQL:范围匹配与周年纪念日

当每组的列值发生变化时 Select 并连接行

这是将表单数据插入 MySQL 数据库的安全方法吗?

安装 mysql-python (Windows)

PHP MySQLI 防止 SQL 注入

我的 PDO 声明不起作用

MySQL - 错误 1045 - 访问被拒绝