news 2026/4/16 10:51:03

MySQL啥时候用记录锁,啥时候用间隙锁?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
MySQL啥时候用记录锁,啥时候用间隙锁?

MySQL 啥时候会用记录锁,啥时候会用间隙锁,啥时候又会用 Next-Key 锁呢?今天我们就来做一些测试,弄清楚这个问题。

文章思维导图

影响因素

在开始之前,我们需要声明的是:本文所有测试及结论的前提均是在「可重复读」隔离级别下,以及 Innodb 存储疫情下。

根据网上资料,我们大概可以知道,影响其使用哪种行级锁的因素有:

  1. 索引类型(聚簇索引、唯一二级索引、普通二级索引)
  2. 匹配类型(精确匹配、唯一匹配、范围匹配)
  3. 事务隔离级别
  4. 是否开启 Innodb_locks_unsafe_for_binlog 系统变量
  5. 记录是否被标记删除
  6. 具体的执行语句类型(SELECT、INSERT、DELETE、UPDATE)

为了让文章相对易懂一些,我准备重点测试索引类型与匹配类型两个影响因素。对于其他的影响因素,我将不做改动。例如:事务隔离级别固定为「可重复读」,Innodb_locks_unsafe_for_binlog 固定为 false。而第 5、6 点相对来说简单一些,则我们会简单带过。

针对上面几个影响因素,我们指定了几个测试实验,分别是:

  1. 聚簇索引 + 精确匹配
  2. 聚簇索引 + 范围匹配
  3. 唯一二级索引 + 精确匹配
  4. 唯一二级索引 + 范围匹配
  5. 普通二级索引 + 精确匹配
  6. 普通二级索引 + 范围匹配
// 表结构 CREATE TABLE `test`.`price_test` ( `id` BIGINT(64) NOT NULL AUTO_INCREMENT, `price` INT(4) NULL, PRIMARY KEY (`id`)); // 表中数据 1, apple, 10 2, orange, 30 50, perl, 60

聚簇索引 + 精确匹配

为了测试「聚簇索引 + 精确匹配」下加锁的类型,我们采用如下的测试方法。

事务 A 执行下面命令:

begin; select * from price_test where id = 2 for update;

执行 show engine innodb status\G; 查看锁信息如下图所示。

可以看到,其是对 id 为 2 的索引加了一个记录锁。

此时事务 B 执行下面命令:

beign; update price_test set price = 25 where id = 2;

执行之后,我们会发现事务 B 阻塞住了。

那如果聚簇索引的值找不到对应的记录呢,将会是一个什么样的结果呢?

我们再来测试一下,开始之前记得将事务 A 和 B 回滚恢复。

事务 A 执行下面命令,其中 id 为 5 的记录是不存在的:

begin; select * from price_test where id = 5 for update;

执行 show engine innodb status\G; 查看锁信息如下图所示。

可以看到,其加了一个间隙锁,该间隙锁应该是 (2, 50) 这个范围。

我们可以通过在事务 B 执行如下命令来测试下间隙锁的范围。

beign; // 执行下面任何一个命令,可以通过 update price_test set price = 25 where id = 2; update price_test set price = 25 where id = 50; // 执行下面任何一个命令,都将阻塞 insert into price_test(id,name,price) values(3,"test",25); insert into price_test(id,name,price) values(5,"test",25); insert into price_test(id,name,price) values(49,"test",25);

由此我们可以得出结论:「聚簇索引 + 精确匹配」,如果能够定位到唯一一条存在的记录,那么其会使用记录锁。如果该记录不存在,那么则会使用间隙锁。

聚簇索引 + 范围匹配

事务 A 执行下面命令:

begin; select * from price_test where id >= 2 for update;

执行 show engine innodb status\G; 查看锁信息如下图所示。

可以看到,事务 A 一共加了 3 个锁,其中 1 个记录锁,2 个 Next-Key 锁。其中 1 个记录锁是对 id 为 2 的索引加的锁,Next-Key 锁是对 (2, 50] 和 (50, 正无穷) 这两个区间加的锁。

在事务 B 执行下面命令可以验证间隙锁的加锁区间:

beign; // 执行下面任意一条语句,都会阻塞 update price_test set price = 25 where id = 2; update price_test set price = 25 where id = 50; insert into price_test(id,name,price) values(5,"test",25); insert into price_test(id,name,price) values(60,"test",25);

这里我们思考一下,如果范围匹配的值并不存在,那么会是什么情况呢?

即事务 A 执行如下语句,其中 id 为 5 的记录是不存在的。

begin; select * from price_test where id >= 5 for update;

执行 show engine innodb status\G; 查看锁信息如下图所示。

可以看到,其实加了 2 个 Next-Key 锁,锁的范围应该是 (2, 50) 和 [50, + 无穷)。

此时事务 B 执行下面命令,应该都会阻塞。

beign; // 执行下面任意一条语句,都会阻塞 update price_test set price = 25 where id = 50; insert into price_test(id,name,price) values(5,"test",25); insert into price_test(id,name,price) values(45,"test",25); insert into price_test(id,name,price) values(60,"test",25);

由此我们可以得出结论:「聚簇索引 + 范围匹配」,会使用「记录锁 + 间隙锁 + Next-Key 锁」。

唯一二级索引 + 精确匹配

事务 A 执行下面命令:

begin; select * from price_test where price = 10 for update;

执行 show engine innodb status\G; 查看锁信息如下图所示。

可以看到,其加的行级锁是 2 个记录锁,应该是 price = 10 这条索引记录的锁。

此时,如果在事务 B 执行下面命令:

beign; // 执行下面任意一条语句,都会阻塞 update price_test set name = 'test-name' where price = 10;

执行之后,我们会发现事务 B 阻塞住了。

由此我们可以得出结论:唯一二级索引与聚簇索引非常类似,都只有一个唯一值,都是使用记录锁。

唯一二级索引 + 范围匹配

事务 A 执行下面命令:

begin; select * from price_test where price >= 30 for update;

执行 show engine innodb status\G; 查看锁信息如下图所示。

可以看到,事务 A 一共有 5 个行锁,其中 3 个 Next-Key 锁, 2 个记录锁。大致可以猜测出两个记录锁分别是 price 为 30 和 60 的记录锁。3 个 Next-Key 锁则是 (10, 30)、(30,60)、(60, 正无穷)三个范围。

为了验证我们上面的结论,我们在事务 B 执行下面命令,每条 SQL 都会阻塞住:

beign; // 执行下面任意一条语句,都会阻塞 update price_test set name = 'price30' where price = 30; update price_test set name = 'price60' where price = 60; insert into price_test(id,name,price) values(5,"test", 20); insert into price_test(id,name,price) values(5,"test", 40); insert into price_test(id,name,price) values(5,"test", 70);

执行之后,我们会发现事务 B 阻塞住了。

由此我们可以得出结论:「唯一二级索引 + 范围匹配」,会使用「记录锁 + 间隙锁 + Next-Key 锁」。

普通二级索引 + 精确匹配

事务 A 执行下面命令:

begin; select * from price_test where name = 'apple' for update;

执行 show engine innodb status\G; 查看锁信息如下图所示。

可以看到,其不仅有一个记录锁,还有一个间隙锁。这里可以猜测记录锁是 apple 索引的记录锁,而间隙锁则是 (负无穷,orange) 的间隙锁。

我们可在事务 B 执行如下命令验证一下:

begin; // 执行下面任意一条语句,都会阻塞 update price_test set name = 'apple-new' where name = 'apple'; insert into price_test(id,name,price) values(5,"aa", 20); insert into price_test(id,name,price) values(5,"ha", 20); // 执行下面的语句正常执行 update price_test set name = 'orange-new' where name = 'orange'; insert into price_test(id,name,price) values(5,"orb", 20);

之所以二级索引的精确匹配会有间隙锁,是因为二级索引可能匹配到多个。因此当匹配到一个的时候,会继续往后匹配,直到匹配到一个不符合的记录,随后就会以该不符合的记录(这里是 orange)作为值做一个间隙锁。

由此我们可以得出结论:「普通二级索引 + 精确匹配」,会使用「记录锁 + 间隙锁 + Next-Key 锁」。

普通二级索引 + 范围匹配

事务 A 执行下面命令:

begin; select * from price_test where name >= 'orange' for update;

执行 show engine innodb status\G; 查看锁信息如下图所示。

从上图可以看到起一共有 2 个记录锁,3 个 Next-Key 锁。其中 2 个记录锁应该是 orange 和 perl 两个记录,3 个 Next-Key 锁,应该是 (apple, orange]、[orange, perl)、[perl, 正无穷)。

我们可在事务 B 执行如下命令验证一下:

begin; // 执行下面任意一条语句,都会阻塞 // 验证记录锁 update price_test set price = 1 where name = 'orange'; update price_test set price = 1 where name = 'perl'; // 验证间隙锁 insert into price_test(id,name,price) values(5,"ba", 20); insert into price_test(id,name,price) values(5,"orb", 20); insert into price_test(id,name,price) values(5,"pes", 20); // 执行下面的语句正常执行 update price_test set price = 1 where name = 'apple'; insert into price_test(id,name,price) values(5,"aa", 20);

可以看到「普通二级索引 + 范围匹配」与「普通二级索引 + 精确匹配」结果是类似的。

我们可以得出结论:「普通二级索引 + 范围匹配」,会使用「记录锁 + 间隙锁 + Next-Key 锁」。

总结

我们做了这么多个测试,虽然有 3 种索引类型(聚簇索引、唯一二级索引、普通二级索引)和 2 种匹配类型(精确匹配、范围匹配),它们两两组合可以得出 6 种情况,再加上查询的值是否存在,可能有更多的可能性。但是我们发现它们的结构都非常类似,基本上都跟查找的记录是否存在,以及查找的记录是否是唯一的相关。

由此,我们大致可以得出结论:

  1. 如果查找的记录是唯一且存在的,那么只会使用记录锁,而不会使用间隙锁或 Next-Key 锁。
  2. 如果查找的记录不唯一或者不存在,那么就会使用 Next-Key 锁和间隙锁。

原文:
https://mp.weixin.qq.com/s/ucmIfX8Jc15CP1pqhzbuZg

作者:树哥聊编程

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/15 10:57:02

综合项目(三):前端页面对接(Vue + Axios)

综合项目(三):前端页面对接(Vue Axios) ——一个老架构师的“别再用 alert() 调接口”的血泪忠告:在电科金仓支撑的学生管理系统里,裸调 API 敏感信息泄露 用户体验崩坏 国产化验收翻车&…

作者头像 李华
网站建设 2026/4/13 17:57:22

毕设项目 stm32与深度学习口罩佩戴检测系统(源码+硬件+论文)

文章目录 0 前言1 主要功能2 硬件设计(原理图)3 核心软件设计4 实现效果5 最后 0 前言 🔥 这两年开始毕业设计和毕业答辩的要求和难度不断提升,传统的毕设题目缺少创新和亮点,往往达不到毕业答辩的要求,这两年不断有学弟学妹告诉…

作者头像 李华
网站建设 2026/4/16 8:40:07

大模型产品岗深度解析:小白也能看懂,如何抓住AI风口?

本文深入分析了当前大模型产品岗的实际情况,指出其并非遍地是机会,而是存在一定的门槛和要求。文章区分了底层/平台/算法侧和应用层/落地场景两类岗位,并强调了专业背景、AI产品实习经历以及落地思维的重要性。同时,文章还探讨了求…

作者头像 李华
网站建设 2026/4/16 7:36:45

TencentOS Server 常见问题

TencentOS Server 有哪些特点 ? TencentOS Server 产品特点如下: 深度定制,开箱即用,无需复杂配置。 安全合规,支持热补丁,零停机修复。 长期支持,拥有强大的运营支撑团队,且全面…

作者头像 李华
网站建设 2026/4/16 7:37:09

热塑性塑料熔体流动速率仪

熔体流动速率仪:热塑性塑料加工性能检测的范式革命 一、标准体系重构:从单一指标到全链条质量管控 热塑性塑料熔体流动速率仪(MFR仪)的发展史,本质上是热塑性塑料质量管控体系的进化史。20世纪70年代,随着聚…

作者头像 李华