mysql触发器语法必须包含for each row,否则报错error 1064;old和new分别访问旧值与新值,禁止修改触发表本身,日志应写入独立审计表并注意字段兼容性与权限。

触发器语法必须包含 FOR EACH ROW
MySQL 的 AFTER UPDATE 触发器不能省略 FOR EACH ROW,否则会报错 ERROR 1064。这是最常被忽略的语法硬性要求,不是可选修饰。
- 正确写法:
CREATE TRIGGER tr_log_after_update AFTER UPDATE ON users FOR EACH ROW ... - 错误写法:
CREATE TRIGGER tr_log_after_update AFTER UPDATE ON users ...(缺FOR EACH ROW) - 触发器体中访问旧值用
OLD.column_name,新值用NEW.column_name,不能反过来
UPDATE 触发器里 OLD 和 NEW 的行为边界
OLD 在 AFTER UPDATE 中仍有效,但要注意:它反映的是更新前的行数据,且仅对被修改的列有意义;未修改的列在 OLD 和 NEW 中值相同。
- 如果只更新了
email字段,OLD.name和NEW.name值一致,但OLD.email != NEW.email - 不能在触发器里修改触发它的表(即不能对
users执行UPDATE或INSERT),否则报错ERROR 1442 - 若需记录变更日志,建议写入另一张表,比如
users_audit
触发器中 INSERT INTO 日志表的实际写法
典型场景是把变更前后字段值存进审计表。注意字段类型匹配、NULL 处理,以及避免因主键冲突或外键约束导致触发器失败。
- 日志表应有独立主键(如自增
id),不要复用原表主键 - 插入时显式列出字段名:
INSERT INTO users_audit (user_id, old_email, new_email, updated_at) VALUES (OLD.id, OLD.email, NEW.email, NOW()) - 如果原表字段允许 NULL,日志表对应字段也应设为
NULL,否则插入OLD.email为 NULL 会失败 - 避免在触发器里调用函数(如
UUID())或子查询,可能影响性能和事务一致性
调试触发器失败时先查 error log 和权限
触发器静默失败很常见,尤其在开发环境没开 log_error_verbosity 时,根本看不到错误堆栈。
- 执行
SHOW ERRORS;紧跟在触发器操作后,能捕获最近一次 SQL 错误 - 确保当前用户对目标表和日志表都有
INSERT权限(触发器以定义者权限运行,但实际执行依赖调用者的权限上下文) - MySQL 8.0+ 默认禁用
log_bin_trust_function_creators,若触发器含函数调用,需显式设置该变量或授予TRIGGER权限











