一文带你弄懂MySQL的加锁规则!

小白debug 2023-09-17 10:25

在之前的文章里,我们讨论了关于 MySQL 的许多问题,包括:

  1. MySQL 啥时候用表锁,啥时候用行锁?
  2. MySQL 不同隔离级别,都使用了什么锁?
  3. MySQL 啥时候用记录锁,啥时候用间隙锁?

在这些文章中,我们大致了解了一些加锁的情况。但实际上 MySQL 的加锁规则是怎样的,我还不是特别清楚。所以今天我们就来深入了解下 MySQL 的加锁规则。

MySQL 的加锁规则到底是怎样的?

迷雾找真相

为了弄清楚这些加锁规则,我查阅了许多资料。但在这些资料中,我觉得比较有质量的只有两个:一个是极客时间《MySQL 45 讲》第 20/21 节讲得内容,另一个是一篇从源码角度解析加锁规则的文章。

《MySQL 45 讲》是丁奇老师出的一个专栏,现在是腾讯云数据库负责人。在该专栏的第 21、22 节中讲到了具体的加锁规则,并且也举了非常多的例子。本文也将摘取其中一些内容,来跟大家讨论学习。

另一篇从源码角度讲加锁规则的,是网名为「小孩子」的网友写得一篇文章,其后续出了一本书叫《从根上了解 MySQL》,内容非常多并且很详细。这篇文章从源码角度从头到尾分析了整个加锁规则,讲得还是比较详细。

在看着两份资料之前,我总是尝试去找到一个简单好记的加锁规律,但看完之后觉得:这或许不太可能。丁奇大神在其专栏也提到他是怎么去分析加锁规则的。

首先说明一下,这些加锁规则我没在别的地方看到过有类似的总结,以前我自己判断的时候都是想着代码里面的实现来脑补的。这次为了总结成不看代码的同学也能理解的规则,是我又重新刷了代码临时总结出来的。

可以看到,就连大神也是想着代码脑补加锁规律的。再结合「小孩子」从源码角度去分析加锁规则,我一下子就觉得:或许还是该深入到源码角度,才能一窥真相。

即使后面丁奇老师为了方便我们理解,也总结出了一些加锁(如下图所示)。但实际上这些加锁规则也没啥规律,只能是记着就好。此外,他也提出:我们需要用动态的眼光去看加锁。言外之意就是,这些规则可能都是变化的,也不一定是完全正确的。

图片来自极客时间专栏

看到这里,我会想:那我们应该怎么学习 MySQL 的加锁规则呢?

我思考了片刻,给出的答案是:我们可以按照丁奇老师总结出的加锁规则先行学习,后续再深入源码层面不断地补足一些细节。

MySQL 加锁全局视角

在讲一些具体加锁规则之前,我觉得有必要先给大家一个 MySQL 加锁的全局视角。这个是丁奇老师在文章中没讲到的,但我觉得如果不知道全局视角,那么会影响到对一些规则的理解。

我们知道 MySQL 分成了 Server 层和存储引擎两部分,每当执行一个查询时,Server 层负责生成执行计划,然后交给存储引擎去执行。其整个过程可以这样描述:

  1. Server 层向 Innodb 获取到扫描区间的第 1 条记录。
  2. Innodb 通过 B+ 树定位到扫描区间的第 1 条记录,然后返回给 Server 层。
  3. Server 层判断是否符合搜索条件,如果符合则发送给客户端,不负责则跳过。接着继续向 Innodb 要下一条记录。
  4. Innodb 继续根据 B+ 树的双休链表找到下一条记录,会执行具体的 row_search_mvcc 函数做加锁等操作,返回给 Server 层。
  5. Server 层继续处理该条记录,并向 Innodb 要下一条记录。
  6. 继续不停执行上述过程,直到 Innodb 读到一条不符合边界条件的记录为止。

通过上面这个过程,我想让大家明白两个重要的认识:

  1. Innodb 并不是一次性把所有数据找到,然后返回给 Server 层的,而是会循环很多次。
  2. row_search_mvcc 这个函数是做具体的加锁、加什么锁的重要逻辑,并且由于 Server 层与 Innodb 会循环多次,因此该函数也是会执行多次的。

弄懂了上面两个认识,会对后续大家理解有很大帮助。例如:对于 select * from user where id >= 5 进行分析的时候,为什么会出现说第一次加锁是精确查询?它明明是范围查询呀!这是因为第一次是要寻找到 id = 5 的记录,对于 Innodb 来说,它就是精确查找,不是范围查找。随后找到 id = 5 的记录之后,就要找 id > 5 的记录了,此时就变成了范围查找了。

MySQL 加锁规则

这里的加锁规则,我直接引用丁奇老师的总结:两个原则、两个优化、一个 bug。

  • 原则 1:加锁的基本单位是 next-key lock。其中 next-key lock 是前开后闭区间,例如:(2, 5]。
  • 原则 2:查找过程中访问到的对象才会加锁。
  • 优化 1:索引上的等值查询,给唯一索引加锁的时候,next-key lock 退化为行锁。
  • 优化 2:索引上的等值查询,向右遍历时且最后一个值不满足等值条件的时候,next-key lock 退化为间隙锁。
  • 一个 bug:唯一索引上的范围查询会访问到不满足条件的第一个值为止。

对于原则 1 说的:加锁的基本单位是 Next-Key 锁,意思是默认都是先加上 Next-Key,之后根据 2 个优化点选择性退化为行锁或间隙锁。

对于原则 2 说的:访问到的对象才会加锁,意思是如果直接索引覆盖到了,不需要回表,那么就不会对聚簇索引加锁。这样的话,其他事务就可以对聚簇索引进行操作,而不会阻塞。

为了解释这些规则,建立表 t 并插入一些数据。

CREATE TABLE `t` (
  `id` int(11) NOT NULL,
  `c` int(11) DEFAULT NULL,
  `d` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `c` (`c`)
) ENGINE=InnoDB;

insert into t values(0,0,0),(5,5,5),
(10,10,10),(15,15,15),(20,20,20),(25,25,25);

等值查询间隙锁

如下图所示的例子,是一个等值条件加间隙锁的例子。

图片来自极客时间专栏

在事务 A 中,要查找 id = 7 的记录,其查找过程为:从左到右查找 id 聚簇索引,依次对比 0、5 两个索引,发现不对。接着,对比 10 这个索引,发现 7 <10,于是停止搜索。根据原则 1 默认给其加上一个 Next-Key 锁,即 (5, 10]。根据优化 2 退化为间隙锁,即 (5,10)。

所以,session B 要插入 id=8 的记录会被锁住,而 session 修改 id=10 这行是可以的。

非唯一索引等值锁

图片来自极客时间专栏

在事务 A 中,要查找 c=5 的记录,其中 c 是非唯一索引。其查找过程为:从左到右查找 c 索引,找到了 c=5 的索引,根据原则 1 对其加 Next-Key 锁,即 (0,5]。

由于普通索引可能重复,因此其还会继续往后搜索,接着搜索到 10,根据原则 2,访问到的都要加锁,因此再给其加 Next-Key 锁,即 (5,10]。由于这个还负责优化 2:等值判断,向右遍历,最后一个不满足等值条件,因此退化为间隙锁 (5,10)。

此外,根据原则 2,只有访问到的对象才会加锁。这个查询使用查询覆盖索引,并不需要访问主键索引,所以主键索引上没有加任何锁。也就是说 (0,5] 和 (5,10) 这两个锁,只在索引 c 上加锁,并不在主键索引上加锁,因此 session B 可以执行。

session C 中插入一个 c 为 7 的值,c 为 7 的值在 (5,10) 之间,因此会被锁住。

主键索引范围锁

对于我们这个表 t,下面这两条查询语句,加锁范围相同吗?

mysql> select * from t where id=10 for update;
mysql> select * from t where id>=10 and id<11 for update;

在逻辑上,这两条查语句肯定是等价的,但是它们的加锁规则不太一样。现在,我们就让 session A 执行第二个查询语句,来看看加锁效果。

图片来自极客时间专栏

我们来分析一下整体的加锁规则吧。

事务 A 开始执行的时候,要找到 id 为 10 的记录,于是从左到右找到了 id 为 10 的索引。根据原则 1 会给其加 Next-Key 锁,即 (5,10]。根据优化 1,id = 10 是等值查询,因此其退化为行锁,即只对 id = 10 这行加了行锁。

接着继续进行范围查找,找到 id=15 这一行,继续加 Next-Key 锁 (10,15]。这时候 id=15 大于 11,因此其不再查找。TODO

非唯一索引范围锁

下面的 c 字段是非唯一普通索引,使用了范围查询。

图片来自极客时间专栏

事务 A 开始执行的时候,要找到 id 为 10 的记录,于是根据原则 1 加了 Next-Key 锁,即 (5,10]。由于索引 C 是非唯一索引,没有优化规则,因此不会退化为行锁。因此对于事务 A 来说,索引 C 上加的是 (5,10] 和 (10,15] 两个 Next-Key 锁。

所以当 session B 和 session C 要操作 c 值为 8 和 15 的数据时会被阻塞。

总结

最后我们总结一下 MySQL 的加锁规则:

  • 首先,明白 server 层与存储引擎层是多次数据交互的,并不是存储引擎层一次性查找完数据。
  • 其次,根据两个原则去分析加锁的范围,核心是加锁单位是 Next-Key 锁。
  • 最后,根据两个优化去进行锁退化,核心因素是唯一索引及等值查询。

其中「两个原则、两个优化」是:

  • 原则 1:加锁的基本单位是 next-key lock。其中 next-key lock 是前开后闭区间,例如:(2, 5]。
  • 原则 2:查找过程中访问到的对象才会加锁。
  • 优化 1:索引上的等值查询,给唯一索引加锁的时候,next-key lock 退化为行锁。
  • 优化 2:索引上的等值查询,向右遍历时且最后一个值不满足等值条件的时候,next-key lock 退化为间隙锁。

通过上面这样的加锁规则,我们就可以有一个大致的分析思路,至少能开始分析加锁规律了。

但要注意的是,实际上的情况非常复杂,例如 limit 参数也会影响加锁的范围,非唯一索引多个值夜会影响锁范围。简单地说,就是有很多特例的情况,我们还需要继续去积累。

参考资料

  • 20 | 幻读是什么,幻读有什么问题?

  • 21 | 为什么我只改一行的语句,锁这么多?

  • 完整版:Innodb 到底是怎么加锁的


评论
  •  光伏及击穿,都可视之为 复合的逆过程,但是,复合、光伏与击穿,不单是进程的方向相反,偏置状态也不一样,复合的工况,是正偏,光伏是零偏,击穿与漂移则是反偏,光伏的能源是外来的,而击穿消耗的是结区自身和电源的能量,漂移的载流子是 客席载流子,须借外延层才能引入,客席载流子 不受反偏PN结的空乏区阻碍,能漂不能漂,只取决于反偏PN结是否处于外延层的「射程」范围,而穿通的成因,则是因耗尽层的过度扩张,致使跟 端子、外延层或其他空乏区 碰触,当耗尽层融通,耐压 (反向阻断能力) 即告彻底丧失,
    MrCU204 2025-01-17 11:30 179浏览
  • 2024年是很平淡的一年,能保住饭碗就是万幸了,公司业绩不好,跳槽又不敢跳,还有一个原因就是老板对我们这些员工还是很好的,碍于人情也不能在公司困难时去雪上加霜。在工作其间遇到的大问题没有,小问题还是有不少,这里就举一两个来说一下。第一个就是,先看下下面的这个封装,你能猜出它的引脚间距是多少吗?这种排线座比较常规的是0.6mm间距(即排线是0.3mm间距)的,而这个规格也是我们用得最多的,所以我们按惯性思维来看的话,就会认为这个座子就是0.6mm间距的,这样往往就不会去细看规格书了,所以这次的运气
    wuliangu 2025-01-21 00:15 181浏览
  • 高速先生成员--黄刚这不马上就要过年了嘛,高速先生就不打算给大家上难度了,整一篇简单但很实用的文章给大伙瞧瞧好了。相信这个标题一出来,尤其对于PCB设计工程师来说,心就立马凉了半截。他们辛辛苦苦进行PCB的过孔设计,高速先生居然说设计多大的过孔他们不关心!另外估计这时候就跳出很多“挑刺”的粉丝了哈,因为翻看很多以往的文章,高速先生都表达了过孔孔径对高速性能的影响是很大的哦!咋滴,今天居然说孔径不关心了?别,别急哈,听高速先生在这篇文章中娓娓道来。首先还是要对各位设计工程师的设计表示肯定,毕竟像我
    一博科技 2025-01-21 16:17 95浏览
  •     IPC-2581是基于ODB++标准、结合PCB行业特点而指定的PCB加工文件规范。    IPC-2581旨在替代CAM350格式,成为PCB加工行业的新的工业规范。    有一些免费软件,可以查看(不可修改)IPC-2581数据文件。这些软件典型用途是工艺校核。    1. Vu2581        出品:Downstream     
    电子知识打边炉 2025-01-22 11:12 46浏览
  • 嘿,咱来聊聊RISC-V MCU技术哈。 这RISC-V MCU技术呢,简单来说就是基于一个叫RISC-V的指令集架构做出的微控制器技术。RISC-V这个啊,2010年的时候,是加州大学伯克利分校的研究团队弄出来的,目的就是想搞个新的、开放的指令集架构,能跟上现代计算的需要。到了2015年,专门成立了个RISC-V基金会,让这个架构更标准,也更好地推广开了。这几年啊,这个RISC-V的生态系统发展得可快了,好多公司和机构都加入了RISC-V International,还推出了不少RISC-V
    丙丁先生 2025-01-21 12:10 111浏览
  • 数字隔离芯片是一种实现电气隔离功能的集成电路,在工业自动化、汽车电子、光伏储能与电力通信等领域的电气系统中发挥着至关重要的作用。其不仅可令高、低压系统之间相互独立,提高低压系统的抗干扰能力,同时还可确保高、低压系统之间的安全交互,使系统稳定工作,并避免操作者遭受来自高压系统的电击伤害。典型数字隔离芯片的简化原理图值得一提的是,数字隔离芯片历经多年发展,其应用范围已十分广泛,凡涉及到在高、低压系统之间进行信号传输的场景中基本都需要应用到此种芯片。那么,电气工程师在进行电路设计时到底该如何评估选择一
    华普微HOPERF 2025-01-20 16:50 73浏览
  • 临近春节,各方社交及应酬也变得多起来了,甚至一月份就排满了各式约见。有的是关系好的专业朋友的周末“恳谈会”,基本是关于2025年经济预判的话题,以及如何稳定工作等话题;但更多的预约是来自几个客户老板及副总裁们的见面,他们为今年的经济预判与企业发展焦虑而来。在聊天过程中,我发现今年的聊天有个很有意思的“点”,挺多人尤其关心我到底是怎么成长成现在的多领域风格的,还能掌握一些经济趋势的分析能力,到底学过哪些专业、在企业管过哪些具体事情?单单就这个一个月内,我就重复了数次“为什么”,再辅以我上次写的:《
    牛言喵语 2025-01-22 17:10 27浏览
  • Ubuntu20.04默认情况下为root账号自动登录,本文介绍如何取消root账号自动登录,改为通过输入账号密码登录,使用触觉智能EVB3568鸿蒙开发板演示,搭载瑞芯微RK3568,四核A55处理器,主频2.0Ghz,1T算力NPU;支持OpenHarmony5.0及Linux、Android等操作系统,接口丰富,开发评估快人一步!添加新账号1、使用adduser命令来添加新用户,用户名以industio为例,系统会提示设置密码以及其他信息,您可以根据需要填写或跳过,命令如下:root@id
    Industio_触觉智能 2025-01-17 14:14 121浏览
  • 现在为止,我们已经完成了Purple Pi OH主板的串口调试和部分配件的连接,接下来,让我们趁热打铁,完成剩余配件的连接!注:配件连接前请断开主板所有供电,避免敏感电路损坏!1.1 耳机接口主板有一路OTMP 标准四节耳机座J6,具备进行音频输出及录音功能,接入耳机后声音将优先从耳机输出,如下图所示:1.21.2 相机接口MIPI CSI 接口如上图所示,支持OV5648 和OV8858 摄像头模组。接入摄像头模组后,使用系统相机软件打开相机拍照和录像,如下图所示:1.3 以太网接口主板有一路
    Industio_触觉智能 2025-01-20 11:04 150浏览
  • 本文介绍瑞芯微开发板/主板Android配置APK默认开启性能模式方法,开启性能模式后,APK的CPU使用优先级会有所提高。触觉智能RK3562开发板演示,搭载4核A53处理器,主频高达2.0GHz;内置独立1Tops算力NPU,可应用于物联网网关、平板电脑、智能家居、教育电子、工业显示与控制等行业。源码修改修改源码根目录下文件device/rockchip/rk3562/package_performance.xml并添加以下内容,注意"+"号为添加内容,"com.tencent.mm"为AP
    Industio_触觉智能 2025-01-17 14:09 161浏览
  •  万万没想到!科幻电影中的人形机器人,正在一步步走进我们人类的日常生活中来了。1月17日,乐聚将第100台全尺寸人形机器人交付北汽越野车,再次吹响了人形机器人疯狂进厂打工的号角。无独有尔,银河通用机器人作为一家成立不到两年时间的创业公司,在短短一年多时间内推出革命性的第一代产品Galbot G1,这是一款轮式、双臂、身体可折叠的人形机器人,得到了美团战投、经纬创投、IDG资本等众多投资方的认可。作为一家成立仅仅只有两年多时间的企业,智元机器人也把机器人从梦想带进了现实。2024年8月1
    刘旷 2025-01-21 11:15 360浏览
  • 日前,商务部等部门办公厅印发《手机、平板、智能手表(手环)购新补贴实施方案》明确,个人消费者购买手机、平板、智能手表(手环)3类数码产品(单件销售价格不超过6000元),可享受购新补贴。每人每类可补贴1件,每件补贴比例为减去生产、流通环节及移动运营商所有优惠后最终销售价格的15%,每件最高不超过500元。目前,京东已经做好了承接手机、平板等数码产品国补优惠的落地准备工作,未来随着各省市关于手机、平板等品类的国补开启,京东将第一时间率先上线,满足消费者的换新升级需求。为保障国补的真实有效发放,基于
    华尔街科技眼 2025-01-17 10:44 221浏览
我要评论
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦