news 2026/9/2 23:35:53

MySQL死锁排查与预防实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
MySQL死锁排查与预防实战

前言

线上日志里突然出现大量这个错误:

Deadlock found when trying to get lock; try restarting transaction

死锁是MySQL高并发场景下的常见问题。偶尔一两次可以通过业务重试解决,但如果频繁出现,就需要从根本上排查和优化。

这篇整理MySQL死锁的排查方法和预防策略。


一、查看死锁信息

MySQL有个命令能看到最近一次死锁的详情:

SHOWENGINEINNODBSTATUS\G

输出很长,找LATEST DETECTED DEADLOCK这部分:

*** (1) TRANSACTION: UPDATE orders SET status = 'paid' WHERE id = 1001 *** (1) HOLDS THE LOCK(S): -- 持有orders表的锁 *** (1) WAITING FOR THIS LOCK: -- 等inventory表的锁 *** (2) TRANSACTION: UPDATE inventory SET quantity = quantity - 1 WHERE product_id = 2001 *** (2) HOLDS THE LOCK(S): -- 持有inventory表的锁 *** (2) WAITING FOR THIS LOCK: -- 等orders表的锁 *** WE ROLL BACK TRANSACTION (2)

经典的死锁场景:事务A锁了orders等inventory,事务B锁了inventory等orders,互相等。

二、分析死锁原因

知道是哪两个SQL了,回去翻代码。

原来下单逻辑里有两种调用顺序:

// 路径A:先改订单再扣库存updateOrderStatus(orderId,"paid");decreaseInventory(productId,1);// 路径B:先扣库存再改订单(另一个接口)decreaseInventory(productId,1);updateOrderStatus(orderId,"paid");

两个接口都在事务里,刚好并发了就死锁。

三、解决方案

最直接的办法:统一加锁顺序

不管哪个接口,都先操作orders再操作inventory(或者反过来,总之要一致)。

// 统一顺序:先orders后inventory@TransactionalpublicvoidprocessOrder(longorderId,longproductId){updateOrderStatus(orderId,"paid");// 永远先锁ordersdecreaseInventory(productId,1);// 再锁inventory}

如果涉及多条记录,按ID排序:

List<Long>ids=Arrays.asList(id1,id2,id3);Collections.sort(ids);for(Longid:ids){lockAndProcess(id);}

四、间隙锁导致的死锁

还有一种更诡异的死锁,两个事务操作的都不是同一行数据。

这通常是间隙锁的问题。RR隔离级别下,SELECT ... FOR UPDATE如果没命中数据,会锁一个"间隙"。

比如user_id有1、5、10三条记录:

-- 事务ASELECT*FROMordersWHEREuser_id=3FORUPDATE;-- 没有user_id=3的数据,但会锁住(1,5)这个间隙-- 事务BSELECT*FROMordersWHEREuser_id=7FORUPDATE;-- 锁住(5,10)这个间隙-- 然后两边各自INSERT-- 事务A想插入user_id=6,要等(5,10)的间隙锁-- 事务B想插入user_id=4,要等(1,5)的间隙锁-- 死锁

解决办法:

  1. 改用RC隔离级别(间隙锁少很多,但要注意幻读)
  2. 用唯一索引精确查询,避免范围锁
SETSESSIONTRANSACTIONISOLATIONLEVELREADCOMMITTED;

五、缩小事务范围

还有个常见问题是事务太长。事务越长,持有锁的时间越久,死锁概率越高。

// 这种写法不好@Transactionalpublicvoidprocess(){queryData();// 查数据callExternalApi();// 调外部接口,可能很慢updateDatabase();// 更新数据库}// 改成这样publicvoidprocess(){queryData();callExternalApi();// 外部调用放事务外面updateInTransaction();}@TransactionalpublicvoidupdateInTransaction(){updateDatabase();// 只有真正需要事务的操作}

六、监控与告警

建议加上监控:

# 简单脚本,每分钟检查死锁次数DEADLOCKS=$(mysql -e"SHOW GLOBAL STATUS LIKE 'Innodb_deadlocks'"|awk'NR==2{print $2}')echo"$(date)deadlocks:$DEADLOCKS">>/var/log/deadlock.log

配合Prometheus的话:

-alert:MySQLDeadlockexpr:increase(mysql_global_status_innodb_deadlocks[5m])>0for:1m

死锁次数涨了就告警,别等业务反馈才知道。

七、业务层重试

有些场景死锁确实很难完全避免,那就在业务层做重试:

intretry=3;while(retry-->0){try{doTransaction();break;}catch(DeadlockExceptione){if(retry==0)throwe;Thread.sleep(100);// 等一下再试}}

MySQL检测到死锁会立即回滚一个事务,不会一直卡着,所以重试通常能成功。


总结

死锁本质是资源竞争问题,预防比解决更重要:

方法效果
统一加锁顺序最有效,从根本上避免死锁
缩小事务范围减少锁持有时间
合理使用索引减少锁的范围
降低隔离级别减少间隙锁(RC级别)
业务层重试兜底方案

记住两点:统一加锁顺序缩小事务范围,能解决大部分死锁问题。


有问题评论区交流。

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

一键利用Erlang SSH高危漏洞获取反向Shell

CVE-2025-32433 Erlang SSH 漏洞利用工具 项目描述 这是一个针对CVE-2025-32433漏洞的Python自动化利用脚本。该漏洞存在于Erlang/OTP的SSH服务器库中&#xff0c;影响OTP-27.3.3、OTP-26.2.5.11和OTP-25.3.2.20之前的版本。攻击者可以利用此漏洞在无需有效凭证的情况下执行任…

作者头像 李华
网站建设 2026/9/2 18:45:41

【开题答辩全过程】以 基于JavaWeb的网上家具商城设计与实现为例,包含答辩的问题和答案

个人简介 一名14年经验的资深毕设内行人&#xff0c;语言擅长Java、php、微信小程序、Python、Golang、安卓Android等 开发项目包括大数据、深度学习、网站、小程序、安卓、算法。平常会做一些项目定制化开发、代码讲解、答辩教学、文档编写、也懂一些降重方面的技巧。 感谢大家…

作者头像 李华
网站建设 2026/9/2 18:44:46

PHP计算机毕设之基于php+vue的家教预约服务网页设计与开发教师资质证书、教学科目、课时费、教学经验(完整前后端代码+说明文档+LW,调试定制等)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华
网站建设 2026/9/2 1:18:13

文档数据库选型痛点频发:为何总在兼容性与成本间持续权衡?

作为企业级数据库架构师或信创项目负责人&#xff0c;你是否经历过这样的场景&#xff1a;在推进核心业务系统国产化替代过程中&#xff0c;面对大量基于MongoDB构建的文档型应用——如用户画像服务、日志分析平台、内容管理系统或IoT设备元数据管理模块——突然发现&#xff1…

作者头像 李华
网站建设 2026/9/2 18:45:48

2026年转行互联网哪些方向更合适?

2022年是疫情管控的终结之年&#xff0c;在这跌宕起伏的一年中&#xff0c;有的行业风生水起&#xff0c;有的行业黯然失色。进入新的2026年&#xff0c;很多人都在考虑要不要转行。那么&#xff0c;2026年的就业市场以及行业未来发展前景是什么样的呢&#xff1f;如果想转行选…

作者头像 李华