2026/6/10 17:35:13
网站建设
项目流程
兼容性视图中显示所有网站,做安全平台网站,电子商务网站业务流程图,wordpress+cms+中文版在高并发业务中#xff0c;MySQL 死锁几乎是绕不开的问题。你可能遇到过这样的报错#xff1a;
Deadlock found when trying to get lock; try restarting transaction死锁并不是 MySQL 的 Bug#xff0c;而是并发设计不当的必然结果。
本文将从 死锁原理、常见场景、排查方…在高并发业务中MySQL 死锁几乎是绕不开的问题。你可能遇到过这样的报错Deadlockfound when tryingtogetlock;tryrestarting transaction死锁并不是 MySQL 的 Bug而是并发设计不当的必然结果。本文将从 死锁原理、常见场景、排查方式、设计规范、Java 实战 五个维度系统讲清楚MySQL 死锁如何避免一、什么是 MySQL 死锁死锁的定义死锁Deadlock 是指多个事务相互持有对方需要的锁并且都在等待对方释放导致所有事务永久阻塞。经典四要素缺一不可条件 说明互斥 锁一次只能被一个事务持有占有并等待 已持有锁的事务继续等待新锁不可剥夺 锁只能由事务主动释放循环等待 多个事务形成等待环MySQL 的 InnoDB 引擎会主动检测死锁并回滚代价最小的事务。二、MySQL 中最常见的死锁场景场景 1不同顺序更新相同资源最常见– 事务 ABEGIN;UPDATE orderSETstatus1WHEREid1;UPDATE orderSETstatus1WHEREid2;– 事务 BBEGIN;UPDATE orderSETstatus2WHEREid2;UPDATE orderSETstatus2WHEREid1; 问题本质A 先锁 id1再锁 id2B 先锁 id2再锁 id1顺序不一致 → 循环等待场景 2范围更新 行更新间隙锁– 事务 A范围锁UPDATE productSETstockstock-1WHEREcategory_id10;– 事务 B单行锁UPDATE productSETstockstock-1WHEREid100; 在 RR 隔离级别 下范围更新会产生 Next-Key Lock行锁 间隙锁容易与单行更新形成死锁场景 3SELECT … FOR UPDATE 使用不当SELECT*FROM accountWHEREuser_id1FORUPDATE;如果没有命中索引锁住大量行多事务交叉执行➡️ 极易引发死锁或长时间锁等待场景 4唯一索引插入并发冲突INSERTINTOuser(username)VALUES(tom);多事务并发插入相同唯一键InnoDB 会先加 共享锁 → 排他锁顺序不当也可能形成死锁三、如何快速定位 MySQL 死锁1️⃣ 查看最近一次死锁信息必会SHOW ENGINEINNODBSTATUS;重点关注LATEST DETECTED DEADLOCK你可以看到哪些事务执行了哪些 SQL等待什么锁持有什么锁线上排查死锁的第一利器2️⃣ 打开死锁日志推荐SETGLOBALinnodb_print_all_deadlocks1;死锁信息会直接写入 MySQL error log方便线上分析。四、避免 MySQL 死锁的 8 条核心原则重点✅ 原则 1统一访问顺序最重要多表 / 多行更新顺序必须一致❌ 错误示例A订单 → 库存B库存 → 订单✅ 正确做法所有事务订单 → 库存✅ 原则 2尽量使用主键 / 唯一索引更新UPDATE orderSETstatus1WHEREid?;避免全表扫描范围锁锁定多余行✅ 原则 3缩小事务范围短事务❌ 错误Transactionalpublicvoidprocess(){select();业务计算();远程调用();update();}✅ 正确select();业务计算();TransactionalpublicvoidupdateDb(){update();} 事务只包数据库操作✅ 原则 4避免无索引的 SELECT FOR UPDATE– 错误可能锁全表SELECT*FROM orderWHEREstatus0FORUPDATE;– 正确SELECT*FROM orderWHEREid?FORUPDATE;✅ 原则 5减少范围更新必要时拆分– 不推荐UPDATE orderSETstatus1WHERE create_time2024-01-01;– 推荐分页 / 按主键批量更新✅ 原则 6合理设置隔离级别如果业务允许SET SESSION TRANSACTION ISOLATION LEVELREADCOMMITTED;减少间隙锁显著降低死锁概率✅ 原则 7并发场景下控制重试机制InnoDB 回滚后应用层应try{// db operation}catch(DeadlockExceptione){// sleep retry} 死锁不可怕不可恢复才可怕✅ 原则 8热点资源做串行化设计例如库存扣减账户余额同一订单状态流转可选方案Redis 分布式锁消息队列串行消费乐观锁version五、Java 高并发场景下的实战建议1️⃣ 使用乐观锁代替悲观锁UPDATE productSETstockstock-1,versionversion1WHEREid?ANDversion?;失败则重试避免大量锁竞争。2️⃣ 库存 / 金额类操作单线程化MQ → 单消费者 → DB这是电商、物流系统的常规做法。3️⃣ 避免“先查再改”的经典坑❌SELECT stock FROM productWHEREid1;UPDATE productSETstockstock-1WHEREid1;✅UPDATE productSETstockstock-1WHEREid1AND stock0;六、总结架构级结论死锁不是偶发事故而是并发设计问题。一句话记住统一顺序索引优先事务要短范围要小必要可重试热点做串行 优秀的系统不是“没有死锁”而是“死锁可控、可恢复、不影响业务”。