MySQL数据库死锁问题的解决方法
MySQL死锁时InnoDB自动回滚代价较小事务并抛出错误码1213,这是正常机制。需通过SHOWENGINEINNODBSTATUS定位冲突SQL及加锁顺序,开启innodb_print_all_deadlocks记录全部死锁。常见根因是SQL执行顺序不一致或索引缺失导致大量行锁冲突。
当MySQL数据库出现死锁时,不少开发者的第一反应是立即修改代码。其实不必着急,InnoDB存储引擎自身具备处理能力——它会自动选择代价较小的事务进行回滚,并返回错误码1213。这并非系统故障,而是InnoDB的正常保护机制主动打破了死锁僵局。真正需要关注的是,找出是哪两条SQL语句在争夺同一组资源,以及它们的加锁顺序为何产生冲突。

死锁发生后不必急于修改代码
MySQL在检测到死锁后,会立即回滚代价较小的事务,并抛出错误消息 Deadlock found when trying to get lock(错误码 1213)。这实际上并不是真正的问题,而是InnoDB引擎的一种自我保护机制——它主动打破了锁等待的死局。真正需要做的是,定位是哪两条SQL语句在争夺同一组资源,并分析它们加锁顺序冲突的根本原因。
使用 SHOW ENGINE INNODB STATUSG 提取死锁现场信息
此命令是排查MySQL死锁最直接且必不可少的方法。执行后,输出信息中只需关注 LATEST DETECTED DEADLOCK 部分,重点关注以下三方面内容,缺一不可:
- 每个事务的
query id后紧跟着的实际SQL,例如UPDATE t SET c = c + 1 WHERE id = 2 - 事务 (1) 的
HOLDS THE LOCK(S)和事务 (2) 的WAITING FOR THIS LOCK TO BE GRANTED——这直接指明了谁先占据了哪些锁、谁在等待什么锁 - 锁类型描述,比如
RECORD LOCKS lock_mode X locks rec but not gap表示主键上的排他记录锁;若出现gap或next-key,说明涉及间隙锁,大概率与范围查询或非唯一索引相关
查不到死锁日志?检查 innodb_print_all_deadlocks 是否已开启
默认情况下,SHOW ENGINE INNODB STATUS 只保留最近一次死锁信息。如果线上频繁报错但日志里找不到上下文,很可能就是因为没有开启全量记录。
- 临时开启(重启失效):
SET GLOBAL innodb_print_all_deadlocks = ON; - 永久生效需写入配置文件:在
[mysqld]下添加innodb_print_all_deadlocks = 1,并确保log_error路径可写 - 注意:开启后所有死锁都会追加进 error log,若不定期清理可能会撑爆磁盘
SQL语句执行顺序不一致是死锁最常见的原因
很多团队总把死锁归为“偶发”,其实只要两个事务更新同一组行但顺序不同,就一定会在足够高的并发下复现。
- 典型例子:
事务 A:UPDATE orders SET status=2 WHERE id=100;→UPDATE users SET last_order_id=100 WHERE id=5;
事务 B:UPDATE users SET last_order_id=101 WHERE id=5;→UPDATE orders SET status=2 WHERE id=101; - 解决方式不是增加重试,而是强制统一操作顺序:比如永远先操作
orders,再操作users - 索引缺失也会放大问题:
WHERE user_id = ?若user_id没有索引,InnoDB 会执行全表扫描并锁定大量行,极易与其他事务产生交叉冲突
真正难以处理的并非单次死锁,而是那些因间隙锁、长事务或ORM自动生成SQL顺序混乱所导致的隐蔽冲突——它们不会立即报错,但会在高并发时突然爆发。
游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。
同类文章
SQL Server多用户并发INSERT幻读解决方案
SQLServer中幻读源于“先查后插”业务的间隙漏洞,SERIALIZABLE隔离级别不能覆盖多语句操作且依赖索引。真正解决需将“读-判-写”绑定为原子动作,如使用MERGE语句、唯一索引加错误捕获或UPDLOCK加HOLDLOCK手动锁范围,并确保查询走索引及显式开启事务。
Django项目利用安全库规避SQL注入的方法
DjangoORM仅对值参数化,字段名等结构参数需白名单校验。filter()动态字段名、raw()和extra()参数化、RawSQL中LIKE手动转义及ORDERBY等结构字段均为注入风险点,需严格规避用户直接控制。
SQL分组统计状态变更次数的方法
通过LAG()窗口函数对比相邻行状态变化并计数,是统计分组内状态改变次数的核心方法。需严格按业务逻辑排序、正确分区,并处理NULL边界。旧版MySQL可考虑导出数据用脚本处理。性能优化需建立复合索引,避免函数影响。状态定义需明确连续相同值过滤等陷阱。
MySQL数据排序的原理与实现步骤
MySQL排序采用文件排序或索引排序,数据量大时使用合并排序。内存排序由sort_buffer_size控制,超限则转磁盘临时表。索引排序效率高,覆盖索引可避免回表。通过EXPLAIN可分析是否使用索引、临时表或文件排序,据此优化性能。
如何定位MySQL撤销日志页锁定导致的检查点延迟
UndoLog页被锁定本身不直接导致CheckPoint延迟,根因是长事务阻塞purge线程导致undo记录无法清理。通过Historylistlength超万且增长、PURGEPROCESSED停滞、事务ID与清理ID差距扩大可判断。定位需查最老活跃事务及其undo段与purge线程状态。
- 热门数据榜
相关攻略
2026-07-12 07:09
2026-07-12 07:08
2026-07-12 07:08
2026-07-12 07:08
2026-07-12 07:08
2026-07-12 07:08
2026-07-12 07:08
2026-07-12 07:08
热门教程
- 游戏攻略
- 安卓教程
- 苹果教程
- 电脑教程

