聊一聊MySQL的记录锁、间隙锁与 Next-Key Lock

news2024/10/5 14:27:09

有小伙伴在微信上表示面试时被问到了 Next-Key Lock 是啥,结果一脸懵逼,那么今天我们来捋一捋 MySQL 中的记录锁、间隙锁以及 Next-Key Lock。

1. Record Lock

Record Lock 也就是我们所说的记录锁,记录锁是对索引记录的锁,注意,它是针对索引记录,即它只锁定记录这一行数据。

例如如下一条 SQL:

select * from user where id=1 for update;

注意,id 是索引,id 如果不是索引,上面这条 SQL 所加的排他锁就不是一个 Record Lock。

我们来看如下一个例子:

首先我们将系统变量 innodb_status_output_locks 设置为 ON,如下:

接下来我们执行如下 SQL,锁定一行数据,此时会自动为表加上 IX 锁:

接下来我们在一个新的会话中执行如下指令来查看 InnoDB 存储引擎的情况:

show engine innodb status\G

输出的信息很多,我们重点关注 TRANSACTIONS,如下:

可以看到:

  • TABLE LOCK table test08.user trx id 3564804 lock mode IX:这句就是说事务 id 为 3564804 的事务,为 user 表添加了意向排他锁(IX)。

  • RECORD LOCKS space id 851 page no 3 n bits 80 index PRIMARY of table test08.user trx id 3564804 lock_mode X locks rec but not gap:这个就是一个锁结构的记录,这里的索引是 PRIMARY,加的锁也是正儿八经的记录锁(not gap)。

看到了 LOCKS REC BUT NOT GAP,就说明这是一个记录锁。

那么这个 Record Lock 和我们之前所讲的 S 锁以及 X 锁有什么区别呢?S 锁是共享锁,X 锁是排他锁,当我们加 S 锁或者 X 锁的时候,如果用到了索引,锁加在了某一条具体的记录上,那么这个锁也是一个记录锁(其实,记录锁,S 锁,X 锁,概念有一些重复的地方,但是描述的重点不一样)。

或者也可以理解为记录锁又细分为 S 锁和 X 锁,它们之间的兼容性如下图:

兼容性S 型记录锁X 型记录锁
S 型记录锁兼容不兼容
X 型记录锁不兼容不兼容

2. Gap Lock

Gap Lock 也叫做间隙锁,它的存在可以解决幻读问题,另外需要注意,Gap Lock 也只在 REPEATABLE READ 隔离级别下有效。先来看看什么是幻读,我们来看如下一个表格:

有两个会话,A 和 B,先在会话 A 中开启事务,然后查询 age 为 99 的用户总数,注意使用当前读,因为在默认的隔离级别下,默认的快照读并不能读到其他事务提交的数据,至于快照读和当前读的区别,大家参考:S 锁与 X 锁,当前读与快照读!。当会话 A 中第一次查询过后,会话 B 中向数据库添加了一行记录,等到会话 A 中第二次查询的时候,就查到了和第一次查询不一样的结果,这就是幻读(注意幻读专指数据插入引起的不一致)。

在 MySQL 默认的隔离级别 REPEATABLE READ 下,上图所描述的情况无法复现。无法复现的原因在于,在 MySQL 的 REPEATABLE READ 隔离级别中,它已经帮我们解决了幻读问题,解决的方案就是 Gap Lock。

大家想想,之所以出现幻读的问题,是因为记录之间存在缝隙,用户可以往这些缝隙中插入数据,这就导致了幻读问题,如下图:

如图所示,id 之间有缝隙,有缝隙就有漏洞。前面我们所说的记录锁只能锁住一条具体的记录,但是对于记录之间的空隙却无能无力,这就导致了幻读(其他事务可往缝隙中插入数据)。

现在 Gap Lock 间隙锁,就是要把这些记录之间的间隙也给锁住,间隙锁住了,就不用担心幻读问题了,这也是 Gap Lock 存在的意义

给一条记录加 Gap Lock,是锁住了这条记录前面的空隙,例如给 id 为 1 的记录加 Gap Lock,锁住的范围是 (-∞,1),给 id 为 3 的记录加 Gap Lock,锁住的范围是 (1,3),那么 id 为 10 后面的空隙怎么锁定呢?MySQL 提供了一个 Supremum 表示当前页面中的最大记录,所以最后针对 Supremum 锁住的范围就是 (10,+∞),这样,所有的间隙都被覆盖到了,由于锁定的是间隙,所以都是开区间。

那么我们怎么样能看到 Gap Lock 呢?我给大家举一个简单的例子,假设我有如下一张表:

CREATE TABLE `user` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `username` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `age` (`age`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

一个简单的表,id 是主键,age 是普通索引,表中有如下几条记录:

接下来我们执行如下 SQL,锁定一行数据,此时也会产生间隙锁:

接下来我们在一个新的会话中执行如下指令来查看 InnoDB 存储引擎的情况:

show engine innodb status\G

输出的信息很多,我们重点关注 TRANSACTIONS,如下:

红色框选中的,就是一个间隙锁的加锁记录,可以看到,在某一个记录之前加了间隙锁。

这就是间隙锁。非常重要的一点需要大家牢记:Gap Lock 只在 REPEATABLE READ 隔离级别下有效

3. Next-Key Lock

以下内容都是基于 MySQL 默认的隔离级别 REPEATABLE READ。

如果我们既想锁定一行,又想锁定行之间的记录,那么就是 Next-Key Lock 了,换言之,Next-Key Lock 是 Record Lock 和 Gap Lock 的结合体。

正常来说,我们加行锁的基本单位就是 Next-Key Lock,即既有记录锁又有间隙锁,但是有时候 Next-Key Lock 会退化,我们通过几个简单的例子来分析一下。

首先我们来看看 Next-Key Lock 的加锁规则:

  1. 锁的范围是左开右闭。

  2. 如果是唯一非空索引的等值查询,Next-Key Lock 会退化成 Record Lock。

  3. 普通索引上的等值查询,向后遍历时,最后一个不满足等值条件的时候,Next-Key Lock 会退化成 Gap Lock。

我们通过几个简单的例子来分析下。

3.1 唯一非空索引

假设我有一个学生表,学生表中有学生的姓名和成绩,如下:

CREATE TABLE `student` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `score` double NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `score` (`score`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

id 是主键,score 是成绩,其中 score 是唯一非空索引。

现在表中有如下数据:

假设我们执行如下 SQL:

在这个例子中,由于 score 是唯一非空索引,所以 Next-Key Lock 会退化成 Record Lock,换句话说,这行 SQL 只给 score 为 90 的记录加锁,不存在 Gap Lock,即我们新开一个会话,插入一条 score 为 88 的记录也是 OK 的。

不过这里有一个特例,如果锁定的是一个不存在的记录,那么也会产生间隙锁,例如下面这个:

由于并不存在 score 为 91 的记录,所以这里会产生一个范围为 (90,95) 的间隙锁,我们执行如下 SQL 可以验证:

可以看到,90.1、94.9 都会被阻塞(我按了 Ctrl C,所以大家看到查询终止)。

90、95 则不符合唯一非空索引的条件。

95.1 则可以插入成功。

没问题。

3.2 非空索引

现在我们重新开始,将 score 索引改为普通索引,如下:

CREATE TABLE `student` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `score` double NOT NULL,
  PRIMARY KEY (`id`),
  KEY `score` (`score`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

数据还是跟前面一样,此时我们来执行如下 SQL:

我们来分析下。

此时要锁定的是 id 为 90 的记录,那么首先加间隙锁,上一个 score 为 89,所以这次加的间隙锁范围是 (89,90),同时要锁定 id 为 90 的记录,所以进一步优化为 (89,90]。

同时,这里还有一条规则,就是满足条件的上一条记录,也需要被锁住,所以最终的锁范围就是 [89,90]。

由于 score 不是唯一性索引,所以还需要继续向后查找,找到的下一条记录是 95,由于此时 Next-Key Lock 会退化成 Gap Lock,所以锁定的范围是 (90,95)。综上,最终锁定的范围是 [89,95)。

接下来我们可以新开一个会话,我们分别尝试添加如下数据看看是否能够添加成功:

可以看到,score 为 88 是可以的,但是为 89.1 就不行。

score 为 95 也是可以的,但是为 94.9 就不行。

再试一下 89 是否可以:

说明我们上面分析的加锁范围是正确的。

再来看如下一条 SQL:

跟前面的案例相比,这次多了 limit 1,limit 1 表示只要一条记录,所以这次查找到 90 之后就不会再往后查找了,那么最终的锁就是间隙锁+一个记录锁,最终的范围就是 [89,90]。

此时新开一个会话,分别插入 score 为 88.9、89、90、91 的 记录,验证我们上面所分析的加锁范围:

88.9 和 89 的插入结果跟我们预想的一致。

可以看到,这里 90 也能插入,能插入的原因是因为缺乏 90 往后的间隙锁。

4. 小结

MySQL 中的锁有点繁杂,小伙伴们可以趁着某个周末,花点时间捋一捋,以后面试再遇到这些问题的时候就不头大了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/102489.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何在小程序中完成支付进件?

1. 完成企业认证 1.1. 创建试用小程序 打开一个待发布的项目。点击顶部导航栏的 发布。手机扫码生成试用小程序。点击二维码底部的 发布应用。 1.2. 使用企业主体 转正小程序选择转正类型为 企业认证。 公司代码。 公司名称。 法人姓名。 法人身份证。 法人微信号。 点…

〖产品思维训练白宝书 - 产品思维认知篇②〗- 破局高手都具备的一种底层认知 - 产品思维

大家好,我是 哈士奇 ,一位工作了十年的"技术混子", 致力于为开发者赋能的UP主, 目前正在运营着 TFS_CLUB社区。 💬 人生格言:优于别人,并不高贵,真正的高贵应该是优于过去的自己。💬 &#x1f4e…

C代码中花括号写成这种风格竟被吐槽~

正文大家好,我是bug菌~最近来了位新同事,闲暇时分聊了几句,其中有一点让我记忆特别深刻,说:"怎么我们这边代码中的花括号风格都独立另起一行,看代码的时候挺不适应的~",我笑着说:"习惯就好了…

CMD CD命令失效,无法到达指定目录?

方法1: a.先进入另一盘的首层。(想进入同盘目录可忽略这步) b.使用cd 进入指定目录。 方法2: 直接进入目录 e:\>cd /d F:\2022F:\2022>cmd的其他指令 内容含义盘符:例如想进入D盘 d:cd进入到当前盘某个目录cd | 进入当前…

[附源码]计算机毕业设计Python个性化名片网站(程序+源码+LW文档)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程 项目运行 环境配置: Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术: django python Vue 等等组成,B/S模式 pychram管理等…

在SpringBoot中操作Redis数据库之StringRedisTemplate

一、RedisTemplate与StringRedisTemplate 二、Redis的五大数据类型 String List Hash Set SortedSet 首先想要在SpringBoot中操作Redis数据库需要先在pom.xml中导入坐标/引入依赖 <dependency><groupId>org.springframework.boot</groupId><arti…

“一体两翼”能否帮助贝壳穿越行业周期?

2022年的房地产行业处于逆周期中&#xff0c;供需双弱和融资困难笼罩在行业上空。数据显示&#xff0c;前三季度&#xff0c;国内百强房企全口径销售金额5.31万亿元&#xff0c;同比下降 45.8%&#xff1b;权益口径销售3.71万亿元&#xff0c;同比下降 46.3%。传统的销售旺季“…

前端:vue-element-admin 搭建踩坑笔记

❤️作者主页&#xff1a;IT技术分享社区 ❤️作者简介&#xff1a;大家好,我是IT技术分享社区的博主&#xff0c;从事C#、Java开发九年&#xff0c;对数据库、C#、Java、前端、运维、电脑技巧等经验丰富。 ❤️个人荣誉&#xff1a; 数据库领域优质创作者&#x1f3c6;&#x…

【MySQL基础教程】MySQL概述、安装与数据模型

前言 本文为 【MySQL基础教程】 相关内容介绍&#xff0c;下边将对MySQL概述&#xff0c;MySQL数据库介绍与安装&#xff08;包括&#xff1a;MySQL数据库版本、MySQL数据库下载、MySQL数据库安装、MySQL启动与停止、客户端连接&#xff09;&#xff0c;数据模型&#xff08;包…

深入浅出学习Linux

Linux作为自由软件有两个特点&#xff1a;一是它免费提供源代码&#xff0c;二是爱好者可以根据自己的需要自由修改、复制和发布源码 Linux的发行版说简单点就是将Linux内核与应用软件做一个打包。 1、Red Hat Linux&#xff08;小红帽&#xff09;&#xff1a;创作于1993年 2…

程序人生与世界杯的火花

卡塔尔世界杯 文章目录1.第一次了解世界杯2.世界杯使用了哪些新技术3.AI 艺术画4.Python代码画了个球状5.踢球和软件团队开发软件有什么异同6.体育是一种国际语言1.第一次了解世界杯 2010年南非世界杯&#xff0c;那会好像记得上大二&#xff0c;学校包车去的五棵松体育馆&…

CSAPP Architecture Lab PartC满分

CSAPP Architecture Lab 此lab涉及Y86-64的实现&#xff0c;具体Y86的内容可查看CSAPP第四章,做完本实验可以提高你对处理器设计以及软件与硬件的理解。 从CMU官网下载完所需实验包后&#xff0c;参考实验所给的官方文档simguide.pdf&#xff0c;首先建立实验环境&#xff0c…

Zookeeper生产常用命令大全(最新3.8.0版本)

文章目录官方文档一、服务端二、客户端1、连接客户端2、help3、create1> 创建持久节点2> 创建临时节点3> 创建持久有序节点4> 创建临时有序节点5> 创建ttl节点6> 创建容器节点4、get5、set6、ls7、stat8、删除节点1> delete2> deleteall8、其他命令二、…

PID算法控制

文章目录一、PID算法二、控制方法对比PID的手动整定PID衰减曲线整定PID调节器各校正环节的作用是&#xff1a;计算注意事项PID算法的一般表达式是&#xff1a;一、PID算法 PID控制是最早发展的自动控制策略之一&#xff0c;是微机化控制系统的一个重要组成部分&#xff0c;整个…

大数据必学Java基础(一百一十五):Session域监听器

文章目录 Session域监听器 一、Session域共有四个监听器接口 二、监听器代码 Session域监听器

学好Python的未来7大就业方向,月薪不低于2w!

最近很多人都有一个问题&#xff1a;“ 我想学 Python&#xff0c;但是学完 Python 后都能干啥 &#xff1f;” “ 现在学 Python&#xff0c;哪个方向最简单&#xff1f;哪个方向最吃香 &#xff1f;” “ …… ” 相信不少 Python 的初学者&#xff0c;都会遇到上面的这些…

[ 数据结构 -- 手撕排序算法第六篇 ] 快速排序(非递归版本)

文章目录前言一、常见的排序算法二、快速排序的非递归版本三、具体步骤四、非递归的代码实现五、时间复杂度4.1最好情况4.2最坏情况六、总结前言 手撕排序算法第六篇&#xff1a;快速排序&#xff01; 从本篇文章开始&#xff0c;我会介绍并分析常见的几种排序&#xff0c;例如…

143744-88-1,标记肽Dansyl-GCVLS

法尼基二磷酸法尼基转移酶(FTase)的荧光底物。该五肽基于H-Ras的c端区域&#xff0c;其n端有一个丹酚基团。由于半胱氨酸巯基的法尼化作用&#xff0c;丹酚基从极性分子环境变为非极性分子环境&#xff0c;伴随而来的是荧光增强和丹酚基向较低波长发射最大值的转移。该产物的完…

【设计模式】代理模式 (六)

文章目录5.1 代理模式5.1.1 概述5.1.2 结构5.1.3 静态代理5.1.4 JDK动态代理5.1.5 CGLIB动态代理5.1.6 三种代理的对比5.1.7 优缺点5.1.8 使用场景5.1 代理模式 5.1.1 概述 由于某些原因需要给某对象提供一个代理以控制对该对象的访问。这时&#xff0c;访问对象不适合或者不…

程序员现状分析,什么时候是进入IT行业的黄金时期?千万注意了

近些来&#xff0c;程序员成为了很多人就业的首选。但是大多数人对于程序员的了解仅仅停留在了薪资待遇上&#xff0c;但是他们对于程序员的工作却所知甚少。甚至有不少人只听说了程序员的工资很高&#xff0c;并不知道程序员的工资会高到什么地步。 其实近些年来&#xff0c;随…