news 2026/5/23 16:06:00

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/5/21 18:29:08

计算机Nodejs毕设实战-基于nodejs的药膳食堂点餐系统的设计与实现基于Node和Vue的点餐平台系统设计【完整源码+LW+部署说明+演示视频,全bao一条龙等】

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

作者头像 李华
网站建设 2026/5/11 23:52:12

STM32启动文件

目录 1.本文启动文件位STM32G030的启动文件&#xff08;.s为结尾的文件&#xff09;&#xff0c;其他型号单片机大同小异&#xff0c;可以直接参考。 我们先来看下启动文件的&#xff0c;开头说明 1、说明 2、启动流程 3、程序分析 1.本文启动文件位STM32G030的启动文件&a…

作者头像 李华
网站建设 2026/5/8 23:06:07

PHP毕设项目推荐-基于PHP的家教预约服务系统预约时间、服务内容、支付记录基于php+vue的家教预约服务网页设计与开发【附源码+文档,调试定制服务】

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

作者头像 李华
网站建设 2026/5/23 11:28:47

国外虚拟乐器app

看了这个app&#xff0c;我才知道什么叫做市场细分--------他不是正对普通人的某一个特定场景&#xff0c;他是直接针对特定人群&#xff0c;这个人群就已经细分了 他是按照职业来划分市场 About this app For musicians from pros to beginners, whether you sing, play a …

作者头像 李华
网站建设 2026/5/8 23:11:09

强烈安利9个降AIGC工具,千笔·降AIGC助手帮你彻底降AI率

AI降重工具&#xff1a;让论文更自然&#xff0c;更安全 随着人工智能技术的广泛应用&#xff0c;越来越多的学生在撰写论文时会借助AI工具进行辅助。然而&#xff0c;AI生成的内容往往带有明显的“AI痕迹”&#xff0c;不仅容易被查重系统识别&#xff0c;还可能影响论文的整体…

作者头像 李华
网站建设 2026/5/23 9:07:37

【课程设计/毕业设计】基于php+vue的矿产资源管理系统矿业资源管理系统的设计与实现【附源码、数据库、万字文档】

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

作者头像 李华