如何在Python Django中快速定位MySQL死锁产生的原因?

秋静同学_2625

秋静同学_2625

2026-07-22

490人浏览

原创

mysql死锁发生时,需通过错误日志、innodb status、information_schema.lock_waits及django异常码1213精准定位谁、在哪、为何卡住,而非仅避免;关键在于可复现、可归因、可收敛。

直接看 mysql 错误日志里的 deadlock found when trying to get lock

只要 django 报出这个错误,就说明死锁已经发生,且 mysql 已回滚了某个事务。关键不是“怎么避免”,而是“这次是谁、在哪、为什么卡住”。log_error 路径可通过 show variables like 'log_error'; 查到,常见位置是 /var/log/mysql/error.log。用 tail -f /var/log/mysql/error.log | grep -i "deadlock" 实时盯住,一出错立刻捕获上下文。

注意:默认只记最近一次死锁;要记录全部,必须在 MySQL 配置里加 innodb_print_all_deadlocks = ON,否则历史死锁信息会被覆盖。

用 SHOW ENGINE INNODB STATUS\G 提取现场快照

这个命令输出很长,但只盯 LATEST DETECTED DEADLOCK 区块就够了。它会明确告诉你:

  • 两个事务各自的 TRANSACTION ID 和执行的 SQL(比如 UPDATE accounts SET balance = ... WHERE id = 1)
  • 哪个事务持有了什么锁(HOLDS THE LOCK(S)),哪个在等什么锁(WAITING FOR THIS LOCK TO BE GRANTED)
  • 被 MySQL 主动回滚的是哪一个(最后一行通常写 WE ROLL BACK TRANSACTION (1))

别跳过“锁住的索引”字段 —— 如果看到 index PRIMARY 是正常行锁,但出现 index GEN_CLUST_INDEX 或没命中索引的 gap lock,说明查询没走索引,锁范围远超预期。

Django 层捕获异常时必须检查 exc.args[0] 是否为 1213

Django 的 DatabaseError 不区分死锁和其他锁等待超时,仅靠字符串匹配 “Deadlock” 容易漏判或误判。真实死锁的底层错误码固定是 1213,而超时是 1205 或其他。

正确做法:

python-code-analyz
python-code-analyz

专业Python代码分析与优化,支持语法检查、安全扫描、性能评估、复杂度分析及重构后优化代码生成。

下载
try:
    with transaction.atomic():
        # 你的 update/select_for_update 操作
        pass
except DatabaseError as exc:
    if exc.args and exc.args[0] == 1213:  # 真死锁
        logger.warning("Deadlock detected: %s", str(exc))
        raise  # 或按需重试
    else:
        raise

不这么做,你就没法把死锁从普通锁等待里筛出来,监控和统计全失真。

查 information_schema.innodb_lock_waits 看实时阻塞链

死锁刚发生后可能还没写进日志,或者你想确认“现在有没有正在卡住的事务”,就跑这条 SQL:

SELECT r.trx_id AS waiting_trx_id,
       r.trx_mysql_thread_id AS waiting_thread,
       r.trx_query AS waiting_query,
       b.trx_id AS blocking_trx_id,
       b.trx_mysql_thread_id AS blocking_thread,
       b.trx_query AS blocking_query
FROM information_schema.innodb_lock_waits w
INNER JOIN information_schema.innodb_trx b ON b.trx_id = w.blocking_trx_id
INNER JOIN information_schema.innodb_trx r ON r.trx_id = w.requesting_trx_id;

结果里每行就是一个“谁在等谁”。如果 waiting_query 和 blocking_query 都来自你的 Django view 或 task,基本就能锁定是哪段代码在交叉加锁。特别注意 trx_state = 'LOCK WAIT' 的事务 —— 它们未必已死锁,但已是高危状态。

真正容易被忽略的点:死锁不是代码 bug,而是并发下资源争抢的必然现象;定位目标不是“消灭死锁”,而是让每次死锁都可复现、可归因、可收敛到少数几个确定路径上 —— 否则你永远在修幻觉。

Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!

相关专题

更多
python打包成可执行文件
python打包成可执行文件

本专题为大家带来python打包成可执行文件相关的文章,大家可以免费的下载体验。

2023.07.20

1631

4

python能做什么
python能做什么

python能做的有:可用于开发基于控制台的应用程序、多媒体部分开发、用于开发基于Web的应用程序、使用python处理数据、系统编程等等。本专题为大家提供python相关的各种文章、以及下载和课程。

2023.07.25

3984

7

format在python中的用法
format在python中的用法

Python中的format是一种字符串格式化方法,用于将变量或值插入到字符串中的占位符位置。通过format方法,我们可以动态地构建字符串,使其包含不同值。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.07.31

1629

3

python教程
python教程

Python已成为一门网红语言,即使是在非编程开发者当中,也掀起了一股学习的热潮。本专题为大家带来python教程的相关文章,大家可以免费体验学习。

2023.08.03

22937

23

python环境变量的配置
python环境变量的配置

Python是一种流行的编程语言,被广泛用于软件开发、数据分析和科学计算等领域。在安装Python之后,我们需要配置环境变量,以便在任何位置都能够访问Python的可执行文件。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.04

2807

5

python eval
python eval

eval函数是Python中一个非常强大的函数,它可以将字符串作为Python代码进行执行,实现动态编程的效果。然而,由于其潜在的安全风险和性能问题,需要谨慎使用。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.04

2847

5

scratch和python区别
scratch和python区别

scratch和python的区别:1、scratch是一种专为初学者设计的图形化编程语言,python是一种文本编程语言;2、scratch使用的是基于积木的编程语法,python采用更加传统的文本编程语法等等。本专题为大家提供scratch和python相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.11

1123

5

python合并两个列表
python合并两个列表

Python是一种强大的编程语言,具有许多方便的功能和工具。在Python中,有多种方法可以合并两个列表。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.10

596

4

python是前端还是后端
python是前端还是后端

Python属于前端也属于后端,其灵活性和丰富的生态系统使得开发人员能够在不同的领域中灵活运用。本专题为大家提供python相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.11

2223

5

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Django 6.1 官方文档
Django 6.1 官方文档

共0课时 | 0人学习

Django 教程
Django 教程

共28课时 | 9.7万人学习

Django DRF 源码解析
Django DRF 源码解析

共21课时 | 2万人学习