与它更近一步,MySql怎么这么多的锁?

news2025/1/16 11:01:47

我们大多都知道行锁锁住的是一行数据,也知道怎么避免行锁造成的阻塞语句问题,但是还是有很多复杂情况,去加了很多锁,如间隙锁以及next-key lock,甚至他们的混合锁,如果这个不了解,搞不好就是语句问题以及死锁问题。

今天通过案例直观的了解下这几种锁,以及出现哪些问题,大家可以先不看下每个解答,而想想出现这个原因是为什么,如果答出来了恭喜你,答不出来也不气馁,本章节学完你就会了!

所以先来看一下锁的规则:

我的版本是MySql5.7版本

间隙锁在可重复读隔离级别下有效,所以本篇无特殊说明,则是在可重复读隔离级别。

林晓斌大神总结出来的加锁规则,大家快记下来,就能应对很多加锁的场景了,这个加锁的规则包含两个“原则”、两个“优化”和一个“bug”。

1.原则1:加锁的基本单位是next-key lock(默认加next-key lock锁),next-key是前开后闭区间。

2.原则2:查找过程中访问到的对象才加锁。

3.优化1:索引上的等值查询,给唯一索引加锁的时候,next-key lock 退化为行锁。

4.优化2:索引上的等值查询,向右遍历时且最后一个值不满足等值条件的时候,next-key lock退化为间隙锁。

5.一个bug:唯一索引上的范围查询会访问到不满足条件的第一个值为止。

请牢记这5条要点,后面会根据此依据看看锁的处理和使用。

我们先来创建个表和数据,来说明的验证下:

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 t VALUES(0,0,0),(5,5,5),(10,10,10),(15,15,15),(20,20,20),(25,25,25)

案例一:等值查询间隙锁

session Asession Bsession C
# 等值查询间隙锁:
begin;
update t set d=d+1 where id=7;

insert into t values(8,8,8)

(blocked)

update t set d=d+1 where id=10;

(query ok)

我们先执行session A里的语句并不提交事务,然后再执行另一个会话session B,插入一条语句然后被阻塞了,然后在执行session C的更新语句发现执行成功了,

这是为什么,为什么插入语句8被阻塞了,而更新id=10就可以?

1.这是因为由于表中没有id=7的记录,所以用我们上面提到的规则的判断的话,根据原则1我们加的是next-key lock,sission A的加锁范围就是(5,10],也就是左开右闭,为什么是(5,10]?我们看下下面的表记录,表中的数据没有7,我们看7在表里是5到10内,所以证明加next-key lock则是(5,10]

 2.同时根据优化2这是一个等值查询id=7,而id=10不满足查询条件,next-key lock退化成间隙锁,因此最终加锁的范围是(5,10)开区间,也就是说这个开区间不包含数字本身,所以session C可以更新。所以sessionB要往这个区间插入id=8的记录会被锁住。

案例二:非唯一索引等值锁

这个例子是关于覆盖索引上的锁:

session Asession Bsession C
begin;
select id from t where c=5 lock in share mode;

update t set d=d+1 where id=5;

(Query OK)

insert into t value(7,7,7);

(blocked)

感觉应该给session B上加锁,为什么又在session C上加锁呢,有一种该锁的没有锁,不该锁的乱锁?

这里session A上给索引c=5这一行加上读锁,

1.根据原则1,我们用next-key lock,因此会给(0,5]加上next-key lock。

2.因为c是普通索引不是唯一索引,因此访问5不会马上停下来,需要向右遍历到c=10才放弃,根据原则2,访问到的数据都要加锁,因此要给(5,10]加next-key lock。

3.但是同时满足优化2,等值判断,向右遍历,最后一个值不满足c=5这个等值条件,因此退化成间隙锁(5,10),此时session C的语句是7存在在(5,10)的区间,所以被阻塞。

4.根据原则2,只有访问到的对象才加锁,这个查询采用的是覆盖索引,并不需要访问主键索引,所以主键索引上没加任何锁,这就是为什么session B的语句可以执行完成。

注意:在这个例子中 lock in share mode 只锁覆盖索引,但是如果是for update 时,系统会认为你接下来要更新数据,因此会顺便给主键索引上满足条件的行加上索引。

同时也是说明,锁是加在索引上的,同时,他给我们的指导是要用 lock in share mode来给行加读锁避免数据被更新的话,就必须得绕过覆盖索引得优化,在查询字段中加入索引中不存在的字段,比如将session A的查询语句改成 select d from t where c=5 lock in share mode;,你可以自己验证下结果,更新的语句也会被阻塞掉。

接下来看一个有趣的案例

案例三:主键索引范围锁

这个案例是关于范围查询的,我们先思考这样两个sql语句,下面的sql语句加锁相同吗?

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

其实,逻辑是相同的,加锁规则却不一样,我们看看

sessin Asession Bsession C
begin; 
select * from t where id>=10  and id < 11 for update;

insert into t value(8,8,8);

(Query OK)

insert into t value(13,13,13);

(blocked)

update t set d=d+1 where id=15;

(blocked)

1.开始执行的时候,找到第一个id=10的行,因此本该是next-key lock(5,10],根据优化1,主键id上的等值条件,退化成行锁,只加了id=10这一行的行锁。

2.范围查找就往后继续找,找到id=15这一行停下来,因此需要加next-key lock(10,15],这样session B的第二条语句,session C语句阻塞你就能够理解了,注意,session A定位查找id=10的行的时候,是等值查询来判断的,向右扫描到id=15,用的是范围查询判断。

咱们来看一下同样例子这个sql语句(select * from t where id=10 for update;)锁的是不是和你想象的一样。

session A session B session C 
begin; 
select * from t where id=10 for update;

insert into t value(8,8,8);

(Query OK)

insert into t value(13,13,13);

(Query OK)

update t set d=d+1 where id=15;

(Query OK)

update t set d=d+1 where id=10;

(blocked)

怎么样是否和你想象的一样呢?这时加的就是行锁。

案例四:非唯一索引范围锁

这个案例与案例三相似,唯一不同的是案例三是主键索引条件,案例四是普通索引,我们来看看

session Asession Bsession C
begin;
select * from t where c>=10  and c < 11 for update;
 

insert into t value(8,8,8);

(blocked)

update t set d=d+1 where c=15;

(blocked)

第一次用c=10定位记录时,索引c加上(5,10]这个next-key lock后,由于索引不是唯一索引,没有优化规则,也就是说不会蜕变为行锁,因此最终加的是(5,10]和(10,15]这两个next-key lock,所以session B和session C被堵住了。

案例五:唯一索引范围锁bug

session Asession Bsession C
begin; 
select * from t where id>10  and id <= 15 for update;

update t set d=d+1 where id=20;

(blocked)

insert into t value(16,16,16);

(blocked)

session B和session C的为什么是这样?

按照规则1的话id索引应该只加(10,15]这个next-key lock,并且因为id是唯一键值,所以循环判断到id=15就可以停止扫描了,但现实是还会向后扫描一个不满足条件为止,这里也就是id=20,而且由于这是个范围扫描,因此索引上也会加(15,20]这个next-key lock也会被锁上。

所以session B就会被堵塞住,按里说id=20这一行是没必要锁住的,因为唯一值只能有一个,作者就认为是个bug,找官方提了bug,但是并未证实。

案例六:非唯一索引上存在“等值”的例子

这个是间隙锁的例子,咱们先插入一个新数据来说明这个例子,这样咱们数据里有两个c字段值为10的了。

insert into t values(30,10,30)

 

session Asession Bsession C
begin;
delete from t where c=10;

insert into t value(12,12,12);

(blocked)

update t set d=d+1 where c=15;

(Query OK)

1.session A遍历到c=10的记录,根据原子1,需要加(5,10]的next-key lock锁,

2.然后再继续查找,直到查找到15这一行,循环结束,根据优化2等值查询,查询不满足条件的行,会退化成间隙锁,所以是(10,15),所以最终5,和10本身的更新不会阻塞,处理10会阻塞,在5和15之间插入会被阻塞住。

 

案例七:limit语句加锁

这个案例和案例6是一个对照,那个执行插入被阻塞,这个插入没有被阻塞,这是怎么一回事呢?

session Asession B
begin;
delete from t where c=10 limit 2;

insert into t value(12,12,12);

(Query OK)

由于我们加了limit 2,表里数据有两条,在遍历第二条满足的条以后,就不再继续找了,因此加锁范围就变成了(5,10],这样session B是可以执行成功的。

 

这个案例也告诉我们,有明确的删除条件我们尽量加limit,不只安全,还减少锁的范围。

案例八:一个死锁的案例

最后一个案例:要说明next-key lock 实际上是间隙锁和行锁加起来的结果。

session A session B

begin;

select id from t where c=10 lock in share mode;

update t set d=d+1 where c=10;

(blocked)

insert into t value(8,8,8);
Deadlock found when trying to get lock; try restarting transaction

1.session A 启动事务后执行查询语句加 lock in share mode,在索引c上加了next-key lock(5,10]和间隙锁(5,10);

2.session B的update语句也要在索引c上加next-key lock(5,10],进入锁等待;

3.然后session A要再插入(8,8,8)这一行,被sessionB的间隙锁锁住,由于出现了死锁,InnoDB让session B回滚。

你可能会问,session B的next-key lock不是还没申请成功吗?

其实是这样的,session B的“加next-key lock(5,10] ”操作,实际上分成了两步,先是加(5,10)的间 隙锁,加锁成功;然后加c=10的行锁,这时候才被锁住的。

也就是说,我们在分析加锁规则的时候可以用next-key lock来分析。但是要知道,具体执行的时 候,是要分成间隙锁和行锁两段来执行的。

怎么样,是不是悟了呢,此篇博客用时7个半小时,创作不易,点赞,关注不过分吧!!
 

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

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

相关文章

为什么流程工业需要合适的预测性维护方案?

在当今工业中&#xff0c;预测性维护是一项至关重要的战略&#xff0c;它能够帮助企业预测设备故障并防止代价高昂的停机。然而&#xff0c;对于流程制造和离散制造来说&#xff0c;选择合适的预测性维护解决方案是至关重要的&#xff0c;因为这两类行业在设备运营和维护方面存…

商机管理是什么?如何有效地进行商机管理?

本篇文章&#xff0c;您可以了解&#xff1a;1、商机管理是什么&#xff1b;2、如何做好商机管理。 在当今竞争激烈的商业世界&#xff0c;商机就像隐藏在茫茫大海中的珍宝&#xff0c;等待着智慧的航海家去发现。作为一名经验丰富的顾问&#xff0c;我将与你一同探索商机管理…

使用idea实现git操作大全(在项目开发中遇到的实际情况

使用idea实现git操作大全&#xff08;在项目开发中遇到的实际情况&#xff09; 1.安装git插件2.在开发中切记拉一个自己的分支 1.安装git插件 2.在开发中切记拉一个自己的分支 选中需要拉的分支&#xff0c;右键该分支&#xff0c;选中new breach from “分支”&#xff0c;点…

2023 电赛 E 题 K210 方案--K210实现矩形识别

相关库介绍 sensor&#xff08;摄像头&#xff09; sensor.reset() sensor.set_pixformat(sensor.RGB565) sensor.set_framesize(sensor.QVGA) sensor.skip_frames(10) reset()&#xff1a;重置并初始化单目摄像头 set_pixformat()&#xff1a;设置摄像头输出格式&#xff0c…

开发框架软件公司:与之携手,共同开启办公流程化之路!

在快节奏的社会里&#xff0c;如何提高企业的办公效率&#xff1f;如何让各部门之间的协作关系更为顺畅&#xff1f;如何把企业内部的数据真正利用起来&#xff0c;成为高层做出经营决策的重要依据&#xff1f;其实&#xff0c;要做到这些&#xff0c;与开发框架软件公司联手合…

无人机机巢有哪些,无人机机场/机场的主要分类

随着无人机技术的飞速发展&#xff0c;无人机已经渗透到了物流、农业、救援、公共安全等多个领域。而为了使这些无人机能更加高效、灵活地运行&#xff0c;一个新的概念应运而生&#xff0c;那就是无人机机巢&#xff08;UAV Nest&#xff09;。复亚智能无人机机巢是一种供无人…

8.3一日总结

1.远程仓库的使用 a.克隆远程仓库 1>.在桌面克隆远程仓库 git clone 仓库名 2>.修改仓库内容 3>添加目录 git add. 4>提交: git commit -m 完成登录功能 5>推送提交远程仓库 : git push origin master -u 6>更改推送:git push(简写形式) 需要先添加,再提交,最…

学习潘海东博士的《潮汐调和分析原理和应用》和调和分析软件S_Tide

潘海东博士在B站&#xff08;用户名&#xff1a;ocean_tide&#xff09;分享了他的电子书《潮汐调和分析原理和应用》&#xff0c;以及他开发的潮汐调和分析工具包S_Tide&#xff0c;非常厉害。 水文同事在进行潮汐预报的时候&#xff0c;会经常说到调和分析和调和常数&#x…

AI无监督异常检测项目记录

前言 半年时间没更新博客&#xff0c;这期间主要验证搞通了几个最适合无监督项目落地的网络&#xff0c;选了几个比较好的网络进行落地部署。 进度 --------------------------------------------------------------------------------------------------------------------…

全面解析大语言模型的工作原理

当ChatGPT在去年秋天推出时&#xff0c;在科技行业乃至世界范围内引起了轰动。当时&#xff0c;机器学习研究人员尝试研发了多年的语言大模型&#xff08;LLM&#xff09;&#xff0c;但普通大众并未十分关注&#xff0c;也没有意识到它们变得多强大。 如今&#xff0c;几乎每个…

ICMP协议(Internet控制消息协议)

系列文章目录 华为数通学习&#xff08;3&#xff09; 目录 前言 一&#xff0c;什么是ICMP协议&#xff1f; 二&#xff0c;实例&#xff1a;路由之间相互直连ping 三&#xff0c;了解ICMP报文 ​编辑 3.1&#xff0c;为什么要了解这个字段呢? 四&#xff0c;ICMP重定…

全国产EtherCAT运动控制边缘控制器(一):ZMC432H硬件接口

为了方便用户了解ZMC432H&#xff0c;本节课程主要给大家介绍一下全国产EtherCAT运动控制边缘控制器ZMC432H的硬件接口与功能。 一、功能简介 全国产EtherCAT运动控制边缘控制器ZMC432H是正运动的一款软硬件全国产自主可控&#xff0c;运动控制接口兼容EtherCAT总线和脉冲型的…

【雕爷学编程】MicroPython动手做(33)——物联网之天气预报2

天气&#xff08;自然现象&#xff09; 是指某一个地区距离地表较近的大气层在短时间内的具体状态。而天气现象则是指发生在大气中的各种自然现象&#xff0c;即某瞬时内大气中各种气象要素&#xff08;如气温、气压、湿度、风、云、雾、雨、闪、雪、霜、雷、雹、霾等&#xff…

软件供应链的基础:SBOM

软件作为一种强大的工具&#xff0c;可以简化复杂的技术概念&#xff0c;但随着软件不可思议的力量而来的是一个相互关联的软件依赖迷宫&#xff0c;这些依赖常常构成软件开发的基础。这些依赖关系并非没有缺陷&#xff0c;正如我们从 Log4Shell 这样的事件中所了解到的那样。当…

详解WebSocket

目录 1.WebSocket是什么&#xff1f; 2.WebSocket的通信过程 3.WebSocket的报文结构 4.JAVA中的WebSocket 1.WebSocket是什么&#xff1f; 在传统的BS体系中&#xff0c;请求响应一直是单向的&#xff0c;服务器一直扮演的”被动“的角色&#xff0c;浏览器发起请求去访问…

FFmpeg常见命令行(一):FFmpeg工具使用基础

前言 在Android音视频开发中&#xff0c;网上知识点过于零碎&#xff0c;自学起来难度非常大&#xff0c;不过音视频大牛Jhuster提出了《Android 音视频从入门到提高 - 任务列表》。本文是Android音视频任务列表的其中一个&#xff0c; 对应的要学习的内容是&#xff1a;FFmpe…

Windows下安装sqlmap及应用

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 Windows下安装sqlmap前提下载安装创建快捷方式修改属性 使用验证安装成功 使用GET猜解是否能注入查找数据库猜解表(假如通过(2)得到了web1这个数据库)根据猜解的表进…

uniApp 插件 Fvv-UniSerialPort 使用实例

接上一篇 uniApp 对接安卓平板刷卡器, 读取串口数据 , 本文将详细介绍如何使用插件读取到串口数据 原理 通过uniApp 插件读取设备串口数据, 解析后供业务使用; 步骤 创建uniApp 项目;添加插件 安卓串口通信 Fvv-UniSerialPort 安卓串口通信 Fvv-UniSerialPort - DCloud 插件…

简单高效的npm地址源管理器

Note: 这个库的灵感来自于使用 nrm 时只切换 npm 的问题 您可以使用此库来帮助npm、cnpm、yarn和pnpm快速切换下载地址源。此外&#xff0c;你还可以指定单个或多个地址源进行切换。 这个库将为您省去切换地址源的许多麻烦&#xff01; 1、为什么使用 但你想要简单快速地切换…

宝塔Linux面板Java项目部署域名访问 (SpringBoot项目)

1. 域名解析 (阿里云) 我的域名是阿里云, 服务器是腾讯云 2. SSL证书申请 (阿里云) 3. 证书签发成功 (阿里云) 4. 下载Nginx证书 (阿里云) 5. 解压获取 .key 和 .pem 文件 6. 添加域名 (腾讯云) 7. 添加域名 (宝塔面板) 8. SSL (宝塔面板) 9. SSL 添加成功 10. 域名访问项目 (成…