on delete cascade 是数据库强制维护引用完整性的级联删除机制,父表记录删除时子表依赖记录必须同步删除,否则报外键约束错误;仅适用于强生命周期绑定关系,需建表时显式声明,且父表被引用列必须有索引。
on delete cascade 是什么,什么时候必须用
它不是可选功能,而是数据库维持引用完整性的强制手段之一——当父表某条记录被删,子表里所有依赖它的记录必须同步消失,否则会报 cannot delete or update a parent row: a foreign key constraint fails。典型场景比如:删掉一个用户,他名下所有订单、地址、收藏都要自动清空;删掉一个分类,其下的所有子分类和商品也得一并清理。
- 只适用于「强生命周期绑定」的关系:子记录没有独立存在意义
- 不能用于可选外键(即允许 NULL 的字段),因为
ON DELETE SET NULL才是它的替代方案 - MySQL 默认不启用该行为,必须显式声明,否则删父表直接报错
建表时直接加 ON DELETE CASCADE 最稳妥
DDL 一次性写对,避免后期修改外键带来的锁表和兼容性风险。尤其在生产环境,ALTER TABLE ... ADD CONSTRAINT 可能触发全表重建或长时间元数据锁。
- 子表创建时就定义好约束:
CREATE TABLE orders ( id INT PRIMARY KEY AUTO_INCREMENT, user_id INT NOT NULL, FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE );
- 注意:被引用的父表主键列(如
users.id)必须有索引(通常是主键),否则 MySQL 拒绝创建外键 - PostgreSQL 和 SQL Server 同样支持该语法,但 SQLite 需开启
PRAGMA foreign_keys = ON才生效
已有表怎么补加级联删除
不能直接 ALTER TABLE ... MODIFY COLUMN 加,必须先删旧约束再建新约束。而 MySQL 不允许用名字直接删匿名外键,得先查出约束名。
- 查当前外键名:
SELECT CONSTRAINT_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE TABLE_SCHEMA = 'your_db' AND TABLE_NAME = 'orders' AND COLUMN_NAME = 'user_id';
- 删旧约束:
ALTER TABLE orders DROP FOREIGN KEY `fk_orders_user_id`;
- 重建带级联的约束:
ALTER TABLE orders ADD CONSTRAINT fk_orders_user_id FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;
- ⚠️ 风险点:操作期间若有人正在插入/删除,可能因外键校验失败而中断事务;建议在低峰期执行
EF Core、Django 等 ORM 里别只配代码不刷库
很多人在 C# 里写了 OnDelete(DeleteBehavior.Cascade),或 Python 里设了 on_delete=models.CASCADE,却忘了真正让数据库生效——ORM 的配置只是生成迁移脚本的依据,不运行 dotnet ef migrations add + update-database,或不执行 python manage.py migrate,数据库本身还是没加 ON DELETE CASCADE。
- 验证方法:连上数据库,查
INFORMATION_SCHEMA.KEY_COLUMN_USAGE或用SHOW CREATE TABLE orders,确认输出里真有ON DELETE CASCADE - EF Core 迁移后若没生效,常见原因是没指定
--context或上下文未正确注册;Django 则要注意makemigrations是否检测到模型变更 - 级联是数据库层行为,ORM 层的软删除(如
is_deleted=True)和它互斥,开了ON DELETE CASCADE就别再靠代码逻辑“假删”
级联删除一旦生效,就不可逆;线上误删父记录会连带清空大量子数据,而 binlog 或 WAL 日志未必能帮你精准回滚到那个时间点。所以关键操作前,务必确认备份已就绪,且有快速验证子表是否残留孤儿记录的检查脚本。










