alter table会参与死锁,因其需加mdl锁并可能持有/等待innodb行锁,且不支持锁等待超时;高危操作包括非末尾加列、建删索引、改列类型、带default加字段及加外键。

Django模型迁移本身不会直接导致MySQL死锁,但迁移过程中执行的ALTER TABLE语句可能触发死锁——尤其当多个迁移并发运行、或迁移与业务SQL交叉执行时。
为什么ALTER TABLE在MySQL里会参与死锁?
MySQL 5.7/8.0 的 ALTER TABLE(尤其涉及索引、外键、列类型变更)在多数情况下需要对表加元数据锁(MDL),并可能在行级锁层面持有或等待 InnoDB 记录锁。它不是原子事务,无法回滚,且不支持锁等待超时配置(不像普通 DML 可设 innodb_lock_wait_timeout)。
- 如果迁移 A 正在
ALTER TABLE users ADD COLUMN balance DECIMAL,它会对users表加MDL_SHARED_WRITE锁,并扫描/重建聚簇索引,期间持续持有行锁 - 此时业务代码恰好执行
UPDATE users SET name = ? WHERE id = 123,就会被阻塞在行锁上 - 若另一笔业务 SQL(比如更新
orders表)又反过来被该迁移阻塞,而该业务 SQL 恰好也试图更新users表某行 —— 就构成典型交叉等待链
哪些迁移操作最容易引发锁冲突?
不是所有迁移都危险,但以下几类在高并发 MySQL 环境中风险突出:
SkillSub Pro - Python 题解与代码注释双功能技能功能概述SkillSub Pro - Python 题解与代码注释双功能技能是一项面向实际任务的技能,主要用于SkillSub Pro 是一个 Python 题解生成与代码注释的 双功能合体技能 ,专为学生、算法学习者和开发者设计;✅ 一个技能,两种用途 :;核心要点📝 题解模式 :输入题目/题号,自动生成完整 Python 题解(含详细注释、解题思路、复杂度分析);💬 注释模式 :输入 Python 代码,自动添加详细中。它将相关步骤、
-
ADD COLUMN且非末尾位置(MySQL 需重建表) -
ADD INDEX或DROP INDEX(尤其在大表上,会持锁扫描) -
MODIFY COLUMN改类型(如VARCHAR(255)→VARCHAR(500)在旧版本需重建) - 带
DEFAULT值的字段添加(MySQL 8.0.12+ 优化为 instant,但低版本仍需写全表) - 外键约束添加(
ADD CONSTRAINT ... FOREIGN KEY会隐式检查参照完整性,锁住关联表)
如何避免迁移过程中的死锁?
核心是「错开 + 降权 + 监控」,而不是依赖 Django 自动处理:
- 禁止在业务高峰期跑迁移;生产环境迁移必须安排在低峰期,且提前通知上下游服务暂停写入
- 用
pt-online-schema-change或gh-ost替代原生migrate执行高危 DDL(它们通过影子表+binlog 回放实现无锁变更) - 在
settings.DATABASES中给 MySQL 连接加'OPTIONS': {'init_command': 'SET SESSION lock_wait_timeout = 10;'},让迁移连接更早放弃等待(注意:仅对 DML 生效,DDL 不受此影响) - 执行前查
SHOW ENGINE INNODB STATUS;确认没有长事务残留(TRX HAS BEEN WAITING FOR超过 60 秒的要 kill) - 用
python manage.py sqlmigrate app_name 0001_initial先看生成的 SQL,人工判断是否含高风险语句(如ALGORITHM=COPY)
迁移报错后残留的锁状态怎么清理?
迁移中断后,MySQL 可能遗留未释放的 MDL 或事务锁,不能靠重启 Django 解决:
- 先查阻塞源:
SELECT * FROM performance_schema.metadata_locks WHERE OBJECT_SCHEMA = 'your_db'; - 再查活跃事务:
SELECT * FROM information_schema.INNODB_TRX ORDER BY trx_started; - 对卡住的
trx_id,用KILL QUERY xxx或KILL xxx终止(注意区分 QUERY 和 CONNECTION) - 别直接删
django_migrations表记录来“跳过”失败迁移——这会让后续迁移基于错误假设继续执行,更容易触发死锁
真正麻烦的从来不是迁移命令输错,而是你改完模型、跑完 makemigrations,却没意识到那条 ALTER TABLE 正在 silently 持有整张表的锁,而线上订单服务正疯狂往里面插数据。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










