当前位置: 首页 > news >正文

mysql死锁排查解决

今天数据库突然报错[40001][1213] Deadlock found when trying to get lock; try restarting transaction 一看就是死锁

阿里实列会显示类似sql:UPDATE goods
SET `num` = `num` - 1
WHERE id=2 AND `num` >= 1;

一看sql这不是扣减库存操作吗? 为什么这sql会出现死锁????????让我百思不得其姐 不得其姐啊

经过复现排查代码 原来 我们扣减库存是 商品ID 从redis购物车读出来 没有统一排序 类似

如图上图所示

死锁原因解析

  1. 并发事务交叉加锁

    • 事务1 按顺序更新 id=1 → id=2,先锁定 id=1

    • 事务2 按顺序更新 id=2 → id=1,先锁定 id=2

    • 此时事务1等待事务2释放 id=2,事务2等待事务1释放 id=1,形成死锁。

  2. MySQL的锁机制特性

    • 当使用 WHERE id IN (a, b) 时,MySQL内部会按主键升序排序后再加锁(即使SQL中顺序不同)。

    • 但若事务中存在多个独立的UPDATE语句(非批量更新),每个语句单独执行,加锁顺序由代码逻辑决定,可能不一致。

解决方案:强制统一加锁顺序

扣减库存前将商品根据ID升序排序再执行扣减库存操作 注意 ID升序排序 ID升序排序 ID升序排序 

为什么必须升序排序?

  • MySQL内部机制:对 IN 列表中的主键,默认按升序排序后加锁(无论SQL写法如何)。批量操作 UPDATE goods set {字段}={值} where id IN(2,1)时mysql底层 就是主键升序排序执行 即便 修改sql: UPDATE goods set {字段}={值} where (select id from goods where id IN(1,2) order by id desc) 时 依旧无法改变升序排序   说到这里有同学可能会问 那:UPDATE goods
    SET `num` = CASE
        WHEN id = 2 AND `num` > 1 THEN `num` - 1
        WHEN id = 1 AND `num` >= 2 THEN `num` - 2
        ELSE `num`
    END
    WHERE id IN (1, 2); 的排序不可以吗 ? WHEN...THEN 写法不适合扣减库存使用 排序是解决了 如果库存不够 依然执行(这有个骚操作 ELSE `num` 改为字符串 让它抛出异常) 但是如果其它业务 需要批量操作 排序又要冲突  所以最好使用升序排序

  • 人为排序保证一致性:显式排序确保代码逻辑与MySQL行为一致,避免隐式依赖。

总结

  • 死锁根因:事务对多行记录加锁顺序不一致 → 循环等待。

  • 终极解法:统一按主键升序访问记录。

  • 扩展优化:乐观锁、事务重试、缩短事务时间。

其他优化建议

  1. 锁超时与重试机制

    • 设置 innodb_lock_wait_timeout 控制锁等待时间。

    • 代码层捕获死锁异常(如 1213 错误),自动重试事务。

  2. 减少事务粒度

    • 尽量缩短事务执行时间,避免长事务持有锁过久。

  3. 乐观锁辅助校验

    • 在商品表中增加 version 字段,更新时校验版本号:

      sql:UPDATE goods SET num = num - 1, version = version + 1 WHERE id = 1 AND version = @old_version;

  4. 隔离级别权衡

    • 使用 READ COMMITTED 隔离级别可减少间隙锁范围,降低死锁概率。

http://www.dtcms.com/a/95520.html

相关文章:

  • Mysql 回表查询,什么是回表查询,如何拒绝sql查询时的回表问题
  • 【Django】教程-3-数据库相关介绍
  • C++中的判断与循环
  • Python 魔术方法功能分类指南
  • 十一、JavaScript简单数据类型和复杂数据类型
  • 材料科学基础:空间群与点群(1)
  • flutter 获取设备的唯一标识
  • 数仓开发那些事(11)
  • chrome-driver安装
  • 【商城实战(77)】商城智能客服系统搭建指南:选型与集成全攻略
  • 大模型有哪些算法
  • 注释容易混淆?修改vscode注释颜色,自定义你的专属颜色
  • Spring Cloud Kubernetes :云原生与容器化部署实战
  • SpringMVC实战——转发和重定向及实际场景
  • Linux中磁盘的管理
  • 对人工智能祛魅了
  • resetForm() 方法用于重置表单
  • 信息隐藏技术
  • Web Services 简介
  • 智能粉尘监测解决方案|守护工业安全,杜绝爆炸隐患
  • 什么是 JavaScript 中的 this 关键字?
  • VS2022 Qt 项目使用数据库报错问题
  • python(26) : 文件上传及下载和预览
  • Spring容器从启动到关闭的注解使用顺序及说明
  • LVS的三种工作模式简述
  • 在linux系统上卸载并重新安装Docker及配置国内镜像源指
  • Open Graph 社交卡片介绍:让网站在社群上被漂亮分享
  • jEasyUI 创建自定义视图
  • 通过TIM+DMA Burst 实现STM32输出变频且不同脉冲数量的PWM波形
  • 漏洞发现:AWVS 联动 XRAY 图形化工具.(主动+被动 双重扫描)