BEFORE DELETE触发器必须用SIGNAL SQLSTATE '45000'中断删除,仅靠RETURN、ROLLBACK或伪错误无效;OLD用于条件判断,TRUNCATE/DROP不触发该触发器,需权限控制兜底。

BEFORE DELETE 触发器必须用 SIGNAL 抛出错误
MySQL 触发器无法用 RETURN、ROLLBACK 或 EXIT 中断删除流程——唯一可靠方式是主动触发异常。只要执行到 SIGNAL SQLSTATE '45000',当前语句立刻终止并回滚,且不进入后续逻辑。
-
SIGNAL必须写在BEFORE DELETE触发器中;AFTER DELETE已无法阻止操作 - SQLSTATE 值建议统一用
'45000'(用户定义异常),避免与系统错误混淆 - 不要依赖
INSERT INTO ... SELECT或DELETE FROM self制造错误——这种“黑魔法”在 MySQL 8.0+ 里可能被优化掉或报更模糊的错误
判断条件要基于 OLD 关键字,别碰 NEW
删除操作没有新数据,NEW 在 BEFORE DELETE 里是 NULL,读取会报错;所有判断必须用 OLD.column_name。
- 比如禁止删 admin 用户:
IF OLD.username = 'admin' THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Deleting admin is forbidden'; - 若需关联其他表判断(如订单未完成不能删客户),得用
SELECT ... INTO @var先查,再比对;但注意性能,别在高频表上做子查询 - 多个条件用
AND/OR组合,别漏括号,否则逻辑短路可能绕过检查
DELIMITER 和语法结构稍错就创建失败
MySQL 默认以分号结束语句,而触发器体内部有多处分号,必须用 DELIMITER 临时改结束符,否则解析器会在第一个分号就截断。
- 正确写法:
DELIMITER //→ 触发器定义 →END //→DELIMITER ; - 常见错误:漏写
DELIMITER //,或END后没跟//,导致报错ERROR 1064 (42000) - 如果用客户端工具(如 DBeaver、Navicat),确认是否自动处理了 delimiter;命令行里必须手动切
触发器不防 DROP TABLE,这点极易被忽略
所有 BEFORE DELETE 触发器只响应 DELETE FROM table,对 DROP TABLE、TRUNCATE TABLE 完全无效——它们属于 DDL,压根不进触发器管道。
- 想拦删表,唯一办法是权限控制:
REVOKE DROP ON db_name.* FROM 'user'@'%' - 用
SHOW GRANTS FOR 'user'@'%'确认输出里不含DROP字样,否则GRANT ALL会悄悄带上它 - 生产环境必须开启审计日志(
audit_log插件或general_log),对含DROP、TRUNCATE的语句实时告警


















