当前位置: 首页 > 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 隔离级别可减少间隙锁范围,降低死锁概率。

相关文章:

  • Mysql 回表查询,什么是回表查询,如何拒绝sql查询时的回表问题
  • 【Django】教程-3-数据库相关介绍
  • C++中的判断与循环
  • Python 魔术方法功能分类指南
  • 十一、JavaScript简单数据类型和复杂数据类型
  • 材料科学基础:空间群与点群(1)
  • flutter 获取设备的唯一标识
  • 数仓开发那些事(11)
  • chrome-driver安装
  • 【商城实战(77)】商城智能客服系统搭建指南:选型与集成全攻略
  • 大模型有哪些算法
  • 注释容易混淆?修改vscode注释颜色,自定义你的专属颜色
  • Spring Cloud Kubernetes :云原生与容器化部署实战
  • SpringMVC实战——转发和重定向及实际场景
  • Linux中磁盘的管理
  • 对人工智能祛魅了
  • resetForm() 方法用于重置表单
  • 信息隐藏技术
  • Web Services 简介
  • 智能粉尘监测解决方案|守护工业安全,杜绝爆炸隐患
  • 专门做优选的网站/网站快速优化排名
  • 网站有域名没备案/互联网广告是做什么的
  • 网站导读怎么做/公司推广宣传文案
  • 东莞建网站公司/目前最流行的拓客方法
  • wordpress 特效/百度seo排名软件
  • 演出备案在哪里查询/衡水网站seo