当你碰到了MySQL中的死锁,你了解这些机制吗?

news2025/8/7 3:40:34

MySQL死锁怎么来的?

当两个及以上的事务,双方都在等待对方释放已经持有的锁或因为加锁顺序不一致造成循环等待锁资源,就会出现“死锁”。

总结一下生产死锁的4个条件:

  1. 两个或者两个以上事务

  2. 每个事务都已经持有锁并且申请新的锁

  3. 锁资源同时只能被同一个事务持有或者不兼容

  4. 事务之间因为持有锁和申请锁导致彼此循环等待

举个例子:用户表,id是主键

事务1

事务2

begin;update user set username = '旭阳' where id = 10;

begin;update user set username = 'alvin' where id = 20;

update user set username = 'alvin' where id = 20;

update user set username = '旭阳' where id = 10;

  • 事务1优先获得了id=10的记录锁

  • 事务2其次获得了id=20的记录锁

  • 然后事务1现在请求id=20的记录锁资源,发现已经被占用了,阻塞等待其他事务释放

  • 同理,事务2请求id=10的记录锁资源,却被事务1占用了

  • 由于事务1和事务2都没有提交,所以他们不会释放锁,导致死锁,得到下面的报错:

​死锁的关键在于:两个(或以上)的事务加锁的顺序不一致。如果上面的事务2也是先锁id=10的记录,再锁id=20的记录,就不会出现死锁。

但是这很难达成,因为我们不同的业务,会有不同的逻辑处理,肯定会出现加锁顺序不一样的情况,特别是在高并发的场景下。

MySQL遇到死锁怎么办?

MySQL发生了死锁,总不能一直让事务现场等在那里,多蠢啊,那它采用什么策略解决死锁问题呢?

  1. 等待,直到超时

即当两个事务互相等待时,当一个事务等待时间超过设置的阈值时,就将其回滚,另外事务继续进行。innoDB存储引擎中,通过innodb_lock_wait_timeout配置设置超时时间,默认50秒。

优点:

  • 简单有效

缺点:

  • 如果真的发生死锁,等待50s这么久一般难以接受,设置太短比如1s, 2s,有可能误触发正常的锁等待。

  1. 使用死锁检测处理死锁程序

由于上面等待的方式太过被动,那有没有可以主动检测出是否存在死锁的方式呢?

MySQL提供了一种主动的死锁检测机制, 相当于将锁等待的信息保存下来,绘制出一个等待的有向图,如下:

​如果检测到存在环,说明有死锁,那么InnoDB存储引擎会选择回滚undo量最小的事务,让其他事务继续执行。

这种机制通过配置 innodb_deadlock_detect控制,默认打开。

​优点:

  • 主动检测,时效性低

缺点: 并发越高,图形越庞大,检测越耗时。每个新的被阻塞的线程,都要判断是不是由于自己的加入导致了死锁,这个操作时间复杂度是O(n)。如果100个并发线程同时更新同一行,意味着要检测100*100=1万次,1万个线程就会有1千万次检测。

上面两种方式并不冲突,默认情况下,MySQL都处于开启状态。

死锁日志怎么看?

虽然MySQL提供了默认的死锁处理机制,更重要的还是我们需要去从业务逻辑代码层面分析发生死锁的根本原因,然后去合理的规避死锁。那为了能够快速定位到死锁相关的业务代码,我们还需要会分析死锁日志。

死锁日志在哪呢?

  1. 通过show engine innodb status命令可以查看最近一次发生死锁的日志。

  2. 通过命令set global innodb_print_all_deadlocks = 1;开启死锁日志记录到MySQL错误日志中,默认情况是不开启的。

​死锁例子超详细解读

我们以上面的用户表为例,解读下死锁日志。

执行命令show engine innodb status获取死锁日志如下图所示:

​LATEST DETECTED DEADLOCK表示InnoDB引擎上次发生的死锁。死锁是至少需要有两个事务参与的,所以在其内部包含了发生死锁的具体两个事务。

  1. 第一个事务 (1) TRANSACTION

  • TRANSACTION 2415258889, ACTIVE 31 sec starting index read

说明: 事务号为2415258889,活跃 31秒,starting index read 表示事务状态为根据索引读取数据。注意删除和更新InnoDB内部也是要进行读操作的。

  • mysql tables in use 1, locked 1

说明: 说明当前的事务使用一个表,并且有一个表锁,DML操作会对表施加意向锁,本例是IX。

  • LOCK WAIT 3 lock struct(s), heap size 1136, 2 row lock(s)

说明: LOCK WAIT 表示正在等待锁,3 lock struct(s)表示 trx->trx_locks 锁链表的长度为3,每个链表节点代表该事务持有的一个锁结构,包括表锁,记录锁以及自增锁等。2 row lock(s)表示当前事务持有的行记录锁/ gap 锁的个数。

  • MySQL thread id 4576535

说明: 表示执行事务的线程id是4576535,即 show processlist; 展示的 ID。

  • update user set username = 'alvin' where id = 20

说明: 表示事务执行正在阻塞的SQL,注意不会显示事务全部执行的SQL

  • (1) WAITING FOR THIS LOCK TO BE GRANTED:

​说明: 这行信息表示等待的锁是一个record lock,空间id是221580,页编号为3,大概位置在页的80位处,锁发生在表user的主键索引上,是一个X锁,但是不是gap lock,waiting表示正在等待锁

  1. 第二个事务 (2) TRANSACTION

第二个事务基本上和第一个事务分析是一样的,我们挑选重要的和不一样的点:

  • (2) HOLDS THE LOCK(S)

​说明: 表明了事务二持有的锁正是事务1想要获取的锁。

  1. WE ROLL BACK TRANSACTION (2)

由于发生了死锁,最终回滚事务2。

我们可以借助死锁日志分析死锁发生可能的原因,但是由于死锁日志只记录发生阻塞的SQL,所以仅仅根据日志也很难以分析死锁的问题的根本原因,但是可以有一定的帮助。

怎么尽量避免死锁?

我们在平时的开发设计有没有一些准则可以帮助我们避免死锁发生?

  1. 合理的设计索引,区分度高的列放到组合索引前面,使业务 SQL 尽可能通过索引定位更少的行,减少锁竞争。

  2. 调整业务逻辑 SQL 执行顺序, 避免 update/delete 长时间持有锁的 SQL 在事务前面。

  3. 避免大事务,尽量将大事务拆成多个小事务来处理,小事务发生锁冲突的几率也更小。

  4. 以固定的顺序访问表和行。比如两个更新数据的事务,事务 A 更新数据的顺序为 1,2;事务 B 更新数据的顺序为 2,1。这样更可能会造成死锁。

  5. 在并发比较高的系统中,不要显式加锁,特别是是在事务里显式加锁。如 select … for update 语句,如果是在事务里(运行了 start transaction 或设置了autocommit 等于0),那么就会锁定所查找到的记录。

  6. 尽量按主键/索引去查找记录,范围查找增加了锁冲突的可能性。

  7. 降低隔离级别。如果业务允许,将隔离级别调低也是较好的选择,比如将隔离级别从RR调整为RC,可以避免掉很多因为gap锁造成的死锁。

总结一下: 也就是在业务允许的情况下,尽量缩短一个事务持有锁的时间、减小锁的粒度以及锁的数量。

总结

本文讲解了MySQL中死锁发生的原因,以及如何通过日志排查死锁,最后给了一些平时开发过程中避免死锁的建议。虽然MySQL会自动解除死锁,但是这个死锁问题以后绝对会再次出现,一定要记住去排除业务SQL的执行逻辑,找到产生死锁的业务,然后调整业务SQL的执行顺序,这样才能从根源上避免死锁产生。

如果本文对你有帮助的话,请留下一个赞吧

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

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

相关文章

[附源码]java毕业设计游戏战队考核系统

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

Baklib帮助中心:自助服务指南

根据 Social endurance 的调查,64%的客户希望在 Twitter 上发帖一小时内得到回复,85%的客户希望公司在6小时内回复。 虽然这种客户期望的趋势几乎适用于所有行业,但某些行业——如电子商务应用程序——的流量正创下历史新高。大多数公司可能…

如何在矩池云上安装语音识别模型 Whisper

如何在矩池云上安装语音识别模型 Whisper Whisper 是 OpenAI 近期开源的一个语音识别的模型,研究人员基于 680,000 小时的标记音频数据进行训练,它同时也是一个多任务模型,可以进行多语言语音识别以及语音翻译任务,可以将语音音频…

【CVPR 2022】QueryDet:加速高分辨率小目标检测

大连不负众望,疫情了,我们又封校了,可能初步封个5678天,微笑jpg 论文地址:https://arxiv.org/pdf/2103.09136.pdf 项目地址:https://github.com/ ChenhongyiYang/QueryDet-PyTorch 1. 简介 背景&#xf…

java中的线程池

文章目录前言线程池的优点线程池的实现原理线程池的创建线程池提交任务线程池的关闭合理配置线程池线程池的监控总结前言 在处理一些比较复杂或者费时的任务的时候,我们常常会选择多线程的方式去处理。那么怎么创建多个线程呢,当然不可能是一个一个创建…

微信如何制作自己的小程序【微信小程序】

小程序在微信的生态中,一直是比较受到企业商家的欢迎, 由于小程序的制作门槛比较低,开发人员可以根据自己喜欢的风格进行定制开发。 微信平台上,很多商家都在为制作小程序而发愁。那么微信如何制作自己的小程序呢? 一…

[附源码]java毕业设计疫情期间物资分派管理系统

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

ebay卖家开店如何做到稳定出单?自养号测评对eBay卖家有什么优势?

ebay卖家开店如何做到稳定出单,有何方法。 1、上架 ebay新账户快速下单的方式是拍卖,但拍卖价格不稳定,可能会让商家赔钱。为了快速打开新账户的局面,商家不妨在早期阶段开始拍卖,因为拍卖是最能驱动流量的。请注意&…

中国互联网众筹行业

近些年,中国互联网发展迅速,众筹这种起源于美国的新型互联网金融模式更是一直处于风口浪尖。在“大众创业、万众创新”的背景下,这种低门槛的融资模式也深受欢迎,加上阿里、京东、苏宁三大电商的巨头的相继入场,更令这…

HDC2022的无障碍参会体验,手语服务是如何做到的?

华为开发者大会2022(HDC)上,HMS Core手语数字人以全新形象亮相,并在直播中完成了长达3个多小时的实时手语翻译,向线上线下超过一千万的观众提供了专业、实时、准确的手语翻译服务,为听障人士提供了无障碍参…

组播技术→

基本概念 224.0.0.0-239.255.255.255 组播IP地址是D类。 224.0.0.0-224.0.0.255 本地网络使用,不进行路由转发。 232.0.0.0–232.255.255.255为特定源组播地址 组播mac地址的高24bit为0x01005e,mac 地址的低23bit为组播ip地址的低23bit。 组播协议 组播通信四要素 源发现…

【SpringBoot 】策略模式 之 一键切换文件上传方式

🎶 文章简介:【SpringBoot 】策略模式 之 一键切换文件上传方式 💡 创作目的:将策略模式的思想融入到java编码中,更加便捷的实现文件上传方式的切换。阿里云Oss对象存储、腾讯云Cos对象存储、七牛云Kodo对象存储以及本…

swift指针内存管理-闭包的循环引用

swift指针&内存管理-引用 无主引用 和弱引用类似,无主引用不会牢牢保持引用的实例。但是不像弱应用,无主引用假定是永远有值的 当我们去访问一个无主引用的时候,总是假定有值的,所以就可能会发生程序的崩溃 如果两个对象的…

单片机的调试接口 JTAG SWD

JTAG-DP 和 SW-DP DP?debug port SW serial wire PA13 JTMS SWDIO ------JTAG 模式选择引脚(JTMS) PA14 JTCK SWCLK ------JTAG时钟引脚(JTCK) PA15 JTDI ------JTAG 数据输入引脚(JTDI) PB3 J…

基于VitePress创建组件文档

我们准备用vitepress做我们的组件文档,方便我们浏览组件,提供使用指南给用户。 安装VitePress 安装: yarn add -D vitepress创建第一个文档: mkdir docs && echo # Hello VitePress > docs/index.md增加脚本命令&a…

十大跑步运动耳机品牌排行榜,值得推荐的六款运动耳机

除了工作时间,大多数人群都喜欢去运动健身,戴着耳机放着喜爱的音乐,慢跑在城市的每个角落里,看着各种事物,悠然自得释放压力的同时还能更加有动力去运动,不得不说,运动确实能够让我们暂时忘却烦…

算法训练Day28 | LeetCode93.复原IP地址(回溯算法中的切割问题2);78 子集(每个节点都收集结果);90.子集II(子集问题+去重)

前言:算法训练系列是做《代码随想录》一刷,个人的学习笔记和详细的解题思路,总共会有60篇博客来记录,记录结构上分为 思路,代码实现,复杂度分析,思考和收获,四个方面。如果这个系列的…

通过DIN算法进行深度特征组合商品推荐 数据+代码(可作为毕设)

案例知识点 推荐系统任务描述:通过用户的历史行为(比如浏览记录、购买记录等等)准确的预测出用户未来的行为;好的推荐系统不仅如此,而且能够拓展用户的视野,帮助他们发现可能感兴趣的却不容易发现的item;同时将埋没在长尾中的好商品推荐给可能感兴趣的用户。 方法概述:…

美团SemEval 2022结构化情感分析跨语言赛道冠军方法总结

总第547篇2022年 第064篇美团语音交互部针对跨语言结构化情感分析任务中缺少小语种的标注数据、传统方法优化成本高昂的问题,通过利用跨语言预训练语言模型、多任务和数据增强方法在不同语言间实现低成本的迁移,相关方法获得了SemEval 2022结构化情感分析…

使用dispatchEvent解决重叠元素响应事件问题

.npm 下的缓存文件太多怎么办?.npm 下缓存的包长时间未清理,占用空间太大怎么办? 查看磁盘占用情况 linux 系统里,查看磁盘占用情况:df -h 1.查看单个目录磁盘占用情况du -sh /指定目录 2.查看所有目录的磁盘占用情况…