最常见原因是外键约束未成功添加或未生效,如建表时遗漏ON DELETE CASCADE、ALTER TABLE未重建约束、存储引擎非InnoDB(MyISAM不支持),或FOREIGN_KEY_CHECKS=0被禁用。

ON DELETE CASCADE 为什么没生效
最常见的情况是:外键约束压根没加成功,或者加了但没生效。比如建表时漏写 ON DELETE CASCADE,或者用 ALTER TABLE 添加外键时只改了列定义、没重新定义约束。MySQL 不会自动把已有外键升级为级联,必须显式重建约束。
另一个隐蔽原因是存储引擎不支持——MyISAM 表完全不支持外键,哪怕语法通过也不会起作用;只有 InnoDB 支持完整外键行为。检查方式:SHOW CREATE TABLE orders,确认引擎是 InnoDB,且外键定义里明确包含 ON DELETE CASCADE。
ALTER TABLE 添加 ON DELETE CASCADE 的正确写法
不能只改列或加索引,必须重建外键约束。步骤如下:
- 先查出原外键名:
SELECT CONSTRAINT_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE TABLE_NAME = 'orders' AND REFERENCED_TABLE_NAME = 'customers' - 删掉旧约束:
ALTER TABLE orders DROP FOREIGN KEY fk_customer_id - 重建带级联的约束:
ALTER TABLE orders ADD CONSTRAINT fk_customer_id FOREIGN KEY (customer_id) REFERENCES customers(id) ON DELETE CASCADE
注意:如果表里已有数据,确保所有 customer_id 值在 customers 表中真实存在,否则 ADD CONSTRAINT 会报错 ERROR 1452。
DELETE 语句执行后子表没删,但也没报错
这往往说明外键约束被绕过了。常见诱因:
-
SET FOREIGN_KEY_CHECKS = 0被意外启用过,之后没恢复(尤其在批量脚本或迁移工具中) - 用户权限不足,导致
ALTER TABLE实际没生效,但错误被忽略 - WHERE 条件没匹配到任何主表记录,看起来“没删”,其实是
DELETE本身没命中数据
验证方法:手动执行 SELECT COUNT(*) FROM order_items WHERE order_id = ?(填一个刚删掉的订单 ID),如果结果非零,说明级联确实没走;再查 SELECT @@FOREIGN_KEY_CHECKS 确认是否为 1。
级联删除在事务中回滚失败的风险点
ON DELETE CASCADE 是引擎层原子操作,它参与事务回滚——这点和触发器有本质区别。但容易被忽略的是:如果子表数据量极大(比如单个订单关联上万条日志),级联删除可能触发锁升级或超长执行时间,导致事务卡住甚至被 innodb_lock_wait_timeout 中断。
此时你看到的现象可能是:主表记录没删成,子表也“好像没动”,但其实 InnoDB 已经对子表部分行加了 X 锁,其他查询被阻塞。排查关键命令:SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX 和 SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS。
真正难调试的是软删除混用场景:主表用 deleted_at IS NULL 标记逻辑删除,但外键仍存在,这时 ON DELETE CASCADE 完全不触发——它只响应物理 DELETE,不响应 UPDATE。


















