mysql如何排查和解决死锁_mysql死锁处理方法

13次阅读

mysql死锁无法完全避免,但可通过开启innodb_print_all_deadlocks、分析SHOW ENGINE INNODB STATUS日志定位原因,并按固定顺序访问表、确保索引命中、缩短事务等优化减少发生;应用层需捕获错误码1213并指数退避重试。

mysql如何排查和解决死锁_mysql死锁处理方法

MySQL死锁无法完全避免,但能快速定位、分析并减少发生频率。关键在于理解死锁成因(多个事务循环等待彼此持有的锁),并借助系统工具获取现场信息,再针对性优化。

查看死锁日志定位原因

MySQL默认开启死锁检测,每次发生后会在错误日志中记录详细信息(InnoDB状态快照)。需确认innodb_print_all_deadlocks=ON(5.6.2+默认关闭,建议开启):

  • 编辑my.cnf,在[mysqld]下添加:innodb_print_all_deadlocks = ON
  • 重启MySQL或动态设置(仅对新连接生效):SET GLOBAL innodb_print_all_deadlocks = ON;
  • 查错日志路径:SHOW VARIABLES LIKE ‘log_error’;,然后用tail -f实时观察

使用SHOW ENGINE INNODB STATUS分析

执行该命令可获取最近一次死锁的完整上下文,重点关注LATEST DETECTED DEADLOCK段:

  • 会显示两个(或多个)事务的SQL、持有锁类型(Record Lock / Gap Lock / Next-Key Lock)、等待锁类型、涉及的表和索引
  • 注意TRANSACTION块中的mysql tables in uselocked tables,判断是否因未走索引导致全表扫描加锁
  • 若看到lock_mode X locks rec but not gap waiting,说明是行锁冲突;若含gap,可能与唯一键冲突或范围查询有关

常见死锁场景与规避方法

多数死锁源于事务内SQL执行顺序不一致或索引失效,而非并发本身:

  • 按固定顺序访问多张表:例如事务A先更新user再更新order,事务B反向操作就易死锁。统一约定“先user后order”可消除循环等待
  • 确保WHERE条件命中索引:无索引的UPDATE/delete会升级为表级意向锁,大幅增加冲突概率。用EXPLAIN验证执行计划
  • 避免长事务:事务越长,持锁时间越久,冲突窗口越大。业务逻辑拆分、减少事务内非DB操作(如远程调用、复杂计算)
  • 减少锁粒度:用主键精确更新代替模糊条件;批量操作拆分为小批次;必要时用selectfor UPDATE SKIP LOCKED跳过已锁定行

应用层应对策略

数据库层优化后仍偶发死锁,应用需具备重试能力:

  • 捕获mysql错误1213(Deadlock found when trying to get lock)
  • 对写操作实现指数退避重试(如100ms、200ms、400ms),最多3次,避免雪崩
  • 读操作一般无需重试,但若依赖强一致性且刚写完就读,可考虑加SELECT … LOCK IN SHARE MODE或调整隔离级别
text=ZqhQzanResources