跳转到主内容
极星编程网:以代码为星,赴技术山海!

mysql死锁如何避免_mysql事务锁优化

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

相关文章