当前位置: 首页 > 知识库问答 >
问题:

mysql - MySQL可重复读隔离级别下,为什么普通索引范围查询临键锁不退化为间隙锁?

周阳波
2025-03-17

MySQL可重复读隔离级别下,普通索引范围查询,小于查询或者小于等于查询,查询到第一个不符合条件的索引时,为什么临键锁不会退化为间隙锁?如果是为了防止幻影数据,可以给出一个例子吗?目前我认为将第一个不满足查询条件的索引可以将临键锁退化为间隙锁,仍然可以防止幻影数据。请各位大佬答疑,感谢!

数据准备

表结构如下:

CREATE TABLE `student` (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
  `age` int DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `student__index_age` (`age`)
) ENGINE=InnoDB AUTO_INCREMENT=22 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci

表中数据SQL及图片

INSERT INTO student (id, name, age) VALUES (1, '路飞', 19);
INSERT INTO student (id, name, age) VALUES (5, '索隆', 21);
INSERT INTO student (id, name, age) VALUES (10, '山治', 22);
INSERT INTO student (id, name, age) VALUES (15, '乌索普', 20);
INSERT INTO student (id, name, age) VALUES (20, '香克斯', 39);

image.png

执行SQL

普通索引范围查询,第一个不符合条件索引,仍然被加临键锁,没有退化为间隙锁
begin;
select * from student where age < 25 for update;
select * from performance_schema.data_locks;
commit;
加锁数据:
二级索引age加锁区间:(-无穷,19],(19,20],(20,21],(21,22],(22,39]
image.png

尝试:普通索引范围查询小于,小于等于条件都尝试过,没有出现第一个不符合条件的索引的临键锁退化为间隙锁的现象。
希望获得结果:为什么不发生退化的原因?

共有1个答案

钱劲
2025-03-17

在MySQL的可重复读(RR)隔离级别下,普通索引范围查询中不发生临键锁退化为间隙锁的根本原因是为了完全防止幻读现象

假设事务A执行:

BEGIN;
SELECT * FROM student WHERE age < 25 FOR UPDATE;
-- 此时不仅会锁住age为19, 20, 21, 22的记录,还会锁住age=39的记录

如果临键锁在遇到第一个不满足条件的记录(age=39)时退化为间隙锁,那么只会锁住(22,39)这个间隙,而不会锁住age=39这个记录本身。

现在考虑如果事务B执行:

BEGIN;
UPDATE student SET age = 24 WHERE age = 39;

如果事务A只有间隙锁而没有临键锁,那么事务B可以成功修改age=39的记录,使其变为age=24。这就导致了幻读问题,因为如果事务A再次执行最初的查询,会发现多了一条记录(原来的age=39现在变成了age=24)。

 类似资料:
  • CREATE TABLE t ( id int(11) NOT NULL AUTO_INCREMENT, k int(11) DEFAULT NULL, PRIMARY KEY (Id), KEY k (k) ) ENGINE=InnoDB DEFAULT CHARSET=latin1; 表里三行数据(0,0)(5,5)(10,10) 我们知道,如果唯一索引等值查询会退化成行锁,比如: selec

  • 以下链接描述了可序列化事务隔离级别。 http://blogs . msdn . com/b/sqlcat/archive/2011/02/20/concurrency-series-basics-of-transaction-isolation-levels . aspx 假设我有一个用户更新表 另一个用户正在更新表 我想序列化这两个更新语句(意味着在第二个语句开始之前等待第一个完成),尽管我们

  • MySQL 提供了  BETWEEN AND 关键字,用来判断字段的数值是否在指定范围内。 BETWEEN AND 需要两个参数,即范围的起始值和终止值。如果字段值在指定的范围内,则这些记录被返回。如果不在指定范围内,则不会被返回。 使用 BETWEEN AND 的基本语法格式如下: [NOT] BETWEEN 取值1 AND 取值2 其中: NOT:可选参数,表示指定范围之外的值。如果字段值不满

  • 我在MySQL中有一个表,它有一个主键列。 有什么建议吗??也许是一个询问..:)

  • 是否可以使用哈希和 我想在查询中比较三个属性。两个是主哈希键和范围键,第三个是本地二级索引的范围键。

  • 我似乎无法找到一个简单的问题的直接答案。如果我在 T-SQL 中创建事务并将隔离级别设置为可序列化,这是否会在我正在修改的表上创建读取锁?

  • 问题内容: 我有一个表,其中包含一列作为CIDR值,例如,我还有其他2列(start_ip_range和end_ip_range),我想填充这2列FROM CIDR列 Java代码可能如下所示: 如何将其转换为MySql查询。 问题答案: 你可以这样转换 询问 样品表 或者,您可以在虚拟列中使用它。因此,您可以直接获得正确的值。 虚拟领域

  • 本文向大家介绍浅析MYSQL REPEATABLE-READ隔离级别,包括了浅析MYSQL REPEATABLE-READ隔离级别的使用技巧和注意事项,需要的朋友参考一下 REPEATABLE-READ 即可重复读,set autocommit= 0或者START TRANSACTION状态下select表的内容不会改变。这种隔离级别可能导致读到的东西是已经修改过的。 比如: 回话一中读取一个字段