没有通用的跨版本触发器语法,mysql 5.7、8.0和postgresql的create trigger语句互不兼容;mysql升级后触发器失效主因是8.0默认启用strict_trans_tables导致非法赋值中断事务,postgresql则强制需先建returns trigger函数再绑定触发器。

没有通用的跨版本触发器语法,MySQL 5.7、8.0 和 PostgreSQL 的 CREATE TRIGGER 语句互不兼容,硬套用只会报错或静默失效。
MySQL 5.7 升级到 8.0 后触发器突然不执行
不是语法错了,而是 sql_mode=STRICT_TRANS_TABLES 默认启用,导致触发器里对 NEW.col 赋非法值(比如向 NOT NULL 字段写 NULL)直接中断事务,而非像 5.7 那样仅警告+截断。
- 检查当前模式:
SELECT @@sql_mode;,确认是否含STRICT_TRANS_TABLES - 避免在
BEFORE INSERT中无条件设NEW.col = NULL;改用IF NEW.col IS NULL THEN SET NEW.col = DEFAULT(col); END IF; - 若必须兼容旧行为,可在触发器开头加
SET sql_mode = 'NO_ENGINE_SUBSTITUTION';,但注意这会影响整条语句上下文
PostgreSQL 触发器报 function does not exist
这不是漏写了触发器,而是没先建函数——PostgreSQL 强制要求两步:先 CREATE FUNCTION 返回 TRIGGER,再 CREATE TRIGGER ... EXECUTE FUNCTION。漏掉任一环节都卡在这错。
- 函数声明必须含
RETURNS TRIGGER,不能是VOID或TEXT - 函数体里访问
NEW或OLD前,得用IF TG_OP = 'INSERT' THEN ... ELSIF TG_OP = 'UPDATE' THEN ... END IF;显式分支 -
BEFORE触发器中修改NEW字段后必须RETURN NEW;AFTER中不能改NEW,否则静默失败
迁移时 dump 文件里没有 CREATE TRIGGER 语句
不是你导出命令写漏了,而是 MySQL 5.7+ 默认启用 --skip-triggers,哪怕加了 --all-databases 也跳过触发器。
- 导出必须显式加
--triggers参数:mysqldump --triggers -u root -p mydb > backup.sql - 导出后立刻验证:
grep -n "CREATE TRIGGER" backup.sql,确保语句真实存在 - 导入前清理目标库已有触发器:
SELECT CONCAT('DROP TRIGGER ', TRIGGER_NAME, ';') FROM information_schema.TRIGGERS WHERE TRIGGER_SCHEMA = 'mydb';,生成并执行结果
触发器里中文变乱码,SHOW CREATE TRIGGER 看不出问题
因为 MySQL 不在元数据里存创建时的字符集,SHOW CREATE TRIGGER 输出永远干净,但运行时按 character_set_client 解析字符串字面量——连的是 latin1,'用户已更新' 就存成乱码字节。
- 所有中文字符串字面量必须加
_utf8mb4前缀:SET @msg = _utf8mb4'用户已更新'; - 别依赖配置文件里的
character_set_server=utf8mb4,它不影响已有触发器的运行时解析逻辑 - CONVERT 或 CAST 只能临时补救字段值,不能根治;真正要改的是表字段字符集和连接环境
最易被忽略的是嵌套调用链:触发器 → 存储过程 → 自定义函数,每个环节都有自己的 DEFINER 和字符集上下文,改一个地方不等于全通。











