能,但必须用SIGNAL主动抛错才能中断删除;仅日志、赋值或查询无效,TRUNCATE和DROP也不触发该触发器。

能,但必须用 SIGNAL 主动抛错,否则删除照常执行;仅写日志、赋值或查表都不起作用。
BEFORE DELETE 触发器里不抛错就等于没写
MySQL 的 BEFORE DELETE 触发器不会自动中断操作。常见错误包括:
- 只执行
INSERT INTO audit_log ...记录行为 —— 删除仍会完成 - 写
SELECT 'blocked'或SET @msg = 'no'—— 完全无效 - 误用 SQL Server 风格的
RAISERROR—— MySQL 不识别,语句直接报错退出,但删除可能已提交
唯一可靠方式是:SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '禁止删除系统账户';
这个错误码兼容 MySQL 5.5+,客户端能捕获并显示提示,应用层可据此做重试或告警。
怎么精准判断哪些行算“敏感数据”
别在触发器里现场查关联表(比如 SELECT COUNT(*) FROM orders WHERE user_id = OLD.id),容易死锁或拖慢主操作。
推荐用本行字段快速判断,例如:
IF OLD.is_protected = 1 THEN SIGNAL ... END IF;IF OLD.role IN ('admin', 'system') THEN SIGNAL ... END IF;IF OLD.id IN (1, 100, 999) THEN SIGNAL ... END IF;
如果业务已有软删字段(如 deleted_at),也建议一并校验:IF OLD.deleted_at IS NULL THEN SIGNAL ... END IF;
TRUNCATE 和 DROP TABLE 根本不走触发器
这是最常被忽略的盲区:TRUNCATE TABLE users 和 DROP TABLE users 是 DDL 操作,BEFORE DELETE 触发器完全不响应。
真正有效的兜底手段只有:
- 用
REVOKE DROP ON mydb.* FROM 'app_user'@'%';剥夺删表权限 - 对高危表禁用
DELETE权限,改用带审批的软删除字段 - 开启
general_log并匹配关键词(如DROP TABLE、TRUNCATE TABLE)自动告警
触发器只是最后一道脆弱防线,不是保险柜。
复杂点在于:触发器逻辑必须轻量、无外部依赖、不查大表;而真正的防护得靠权限分级 + 应用层约束 + 日志审计三层叠加。单靠一个 SIGNAL 语句,撑不起生产环境的数据安全。


















