before delete触发器在删除前执行,可用于拦截非法删除(如signal抛错)、清理关联数据或记录删除意图;仅可读取old值,不可修改,且必须用delimiter和begin/end包裹。

BEFORE DELETE触发器能做什么
它在删除语句执行前介入,可用于阻止非法删除、清理关联数据、记录删除意图或修改即将被删的行(但注意:DELETE 没有 NEW,只有 OLD,所以不能“改要删的数据”,只能读取或抛错)。
语法必须带 DELIMITER 和 BEGIN/END
哪怕只有一条语句,也建议统一用 BEGIN ... END 包裹,避免后续扩展时出错。更重要的是,DELIMITER 必须改——否则 MySQL 会把触发器体内的分号当成语句结束,直接报错 ERROR 1064。
- 先执行
DELIMITER // - 写
CREATE TRIGGER语句,结尾用// - 最后执行
DELIMITER ;恢复默认
只能读 OLD,不能 SET OLD.column
OLD 在 BEFORE DELETE 中是只读的,你只能查它的值(比如 OLD.id、OLD.status),不能赋值。想拦住删除?得用 SIGNAL SQLSTATE '45000' 抛异常。
常见错误写法:SET OLD.deleted_at = NOW() —— 这会报错 ERROR 1362: Updating of OLD row is not allowed in trigger。
正确拦截示例:
DELIMITER //
CREATE TRIGGER prevent_delete_if_active
BEFORE DELETE ON users
FOR EACH ROW
BEGIN
IF OLD.status = 'active' THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Active user cannot be deleted';
END IF;
END//
DELIMITER ;
一个表同一事件+时机只能有一个 BEFORE DELETE 触发器
MySQL 不允许重复定义:ERROR 1359: Trigger already exists。删旧的再建新的,或者用 DROP TRIGGER IF EXISTS trigger_name 前置清理。
另外,触发器不支持事务回滚控制——如果触发器里执行了 INSERT 或 UPDATE,而主 DELETE 失败,那些操作不会自动回滚(InnoDB 下整个事务会回滚,但逻辑上你不该依赖这个行为)。
真正容易被忽略的点:触发器无法捕获 TRUNCATE TABLE,它绕过触发器机制。需要拦截全量删除,得靠权限控制或应用层兜底。











