MySQL死锁无法完全避免,关键在优化事务设计:缩短锁持有时间、统一加锁顺序、确保SQL走索引、拆分批量操作、按主键升序查询、禁用动态SQL,并合理配置超时与重试机制。
死锁不是“避免”而是“减少概率”,关键在事务设计
MySQL 死锁无法完全避免,因为它是 InnoDB 在并发更新同一组行时的正常保护机制。真正要做的,是让事务持有锁的时间更短、加锁顺序更一致、冲突路径更可控。
常见错误现象:
不代表代码有 bug,但频繁出现说明事务结构不合理。
所有
/
语句必须走索引,否则会升级为表级锁或间隙锁,大幅增加死锁面
事务中先
再修改,不如直接
—— 多一次加锁就多一次竞争机会
批量操作拆成小事务,比如 1000 行分 10 次提交,比单个事务锁 1000 行安全得多
加锁顺序不一致是死锁主因,必须统一
两个事务按不同顺序更新
和
表,就极易触发死锁。InnoDB 不保证语句执行顺序,但可以强制业务层约定顺序。
使用场景:微服务间调用、订单创建含用户扣款、库存预占+日志写入等多表更新逻辑。
约定“先操作主表(如
),再操作从表(如
)”,并在所有服务中严格遵守
用
时,务必按主键升序查,例如
,避免因查询优化器打乱顺序导致加锁错位
避免在事务中动态拼接 SQL 或依赖子查询结果决定下一步更新哪张表——这会让加锁路径不可预测
和
不是救命稻草
调大
只会让死锁等待更久,反而拖垮连接池;关掉
在高并发下可能引发锁等待雪崩。
MySQL(Linux)
MySQL 9.6.0是面向Linux平台的2026年创新版本,核心架构迎来重大革新。其将外键约束与级联操作从InnoDB引擎层上移至SQL层,确保所有数据变更均被完整记录至Binlog,彻底解决了CDC(变更数据捕获)与主从复制中的数据不一致难题。此外,该版本引入container_aware启动选项以原生适配容器环境,并对审计日志进行了组件化重构,为追求极致数据一致性与云原生体验的开发者提供了全新选择。
下载
性能与兼容性影响:
(默认)是必要开销,5.7+ 已优化为局部检测,不必担心 CPU 爆涨
建议保持默认 50 秒,应用层应主动设更短的超时(如 3–5 秒),并捕获
后退避重试
不要用
动态改,连接复用下容易污染其他请求
如何快速定位谁在抢同一行?看
它输出的
区块,比任何监控都直接。重点不是看“哪个事务赢了”,而是比对两段
下的
和
行。
实操建议:
每次上线前,在测试环境故意构造双事务交叉更新,跑一遍
,确认锁顺序是否符合预期
线上出死锁后,立刻抓取该命令输出,重点关注
后面的
和主键值,反推是哪几行被争抢
配合
查当前长事务,常是死锁温床——特别是没 COMMIT 的交互式连接
最易被忽略的一点:唯一索引冲突也会触发死锁。比如两个事务同时
,而
是唯一键,InnoDB 会在 duplicate key 检查时加意向锁,照样可能卡住。这种场景下,应用层幂等控制比调参数更治本。
Deadlock found when trying to get lock; try restarting transactionUPDATEDELETESELECT ... FOR UPDATEUPDATEuserorderuserorderSELECT ... FOR UPDATESELECT * FROM order WHERE id IN (10,5,8) ORDER BY idinnodb_lock_wait_timeoutinnodb_deadlock_detectinnodb_lock_wait_timeoutinnodb_deadlock_detectinnodb_deadlock_detect = ONinnodb_lock_wait_timeoutDeadlock found...SET SESSION innodb_lock_wait_timeout = 5SHOW ENGINE INNODB STATUSLATEST DETECTED DEADLOCKTRANSACTIONmysql tables in useLOCK WAITSHOW ENGINE INNODB STATUS*** (1) WAITING FOR THIS LOCK TO BE GRANTED:RECORD LOCKS space idSELECT * FROM information_schema.INNODB_TRXINSERT INTO t (uid) VALUES (123)uid