MySQL 5.7及之后版本支持单表多个同类型触发器,需用FOLLOWS/PRECEDES显式指定执行顺序;5.6及更早版本仅允许每种(timing, event)组合一个触发器。

触发器里用 AFTER INSERT, UPDATE, DELETE 还是分开写?
MySQL 5.7 和 8.0 都支持多事件语法,但 PostgreSQL 完全不认 AFTER INSERT, UPDATE, DELETE——它要求每个事件单独定义触发器函数。SQLite 则压根不支持多事件触发器(只允许单事件)。所以别图省事写成一行,否则在 PostgreSQL 或 SQLite 上直接报错 syntax error near ','。
实操建议:
- 为 PostgreSQL 和 SQLite 单独建三个触发器,分别绑定
INSERT、UPDATE、DELETE - MySQL 可以复用同一函数,但触发器定义仍需拆成三条(兼容性更稳)
- 避免在触发器体里用
IF TG_OP = 'INSERT'这类 PostgreSQL 特有变量——MySQL 和 SQLite 没这玩意
NEW 和 OLD 在不同数据库里怎么安全取值?
PostgreSQL 的 NEW/OLD 是记录类型,MySQL 是行内字段引用,SQLite 是伪表名。最常踩的坑是:在 DELETE 触发器里访问 NEW.id —— SQLite 和 PostgreSQL 都会报 no such column: NEW.id,因为 NEW 在删除时为空。
实操建议:
-
INSERT时只读NEW.*,DELETE时只读OLD.*,UPDATE才两者都可用 - MySQL 中用
IFNULL(NEW.id, OLD.id)混用是危险的——UPDATE 时没问题,INSERT/DELETE 会出错 - 统一用显式判断:PostgreSQL 写
IF TG_OP = 'INSERT' THEN ... END IF;;MySQL 和 SQLite 则靠触发器定义本身隔离事件类型,函数体内不混逻辑
同步逻辑里调用外部服务,为什么 MySQL 触发器总卡住?
MySQL 触发器禁止执行 INSERT INTO remote_log 以外的跨库/网络操作(比如调用 sys_exec() 或 UDF),强行调用会报 ERROR 1422: Explicit or implicit commit is not allowed in stored function or trigger。PostgreSQL 允许 pg_notify() 或异步队列,SQLite 根本没网络能力。
实操建议:
- 所有数据库统一走「写本地同步表 + 外部轮询」模式,例如插入一条
sync_queue记录,含table_name、row_id、op_type - 避免在触发器里做 JSON 序列化——MySQL 5.7 没原生 JSON 函数,得拼字符串;PostgreSQL 有
row_to_json(),但 SQLite 要靠应用层补 - 字段名别用
timestamp这种关键字,MySQL 和 PostgreSQL 对大小写和保留字敏感度不同,容易在某一个版本里莫名失败
如何让同一个 SQL 文件在三套数据库里都能跑通?
没有“一份 SQL 脚本通用三库”这种捷径。真正的兼容靠的是分层:SQL 文件里只放标准 DML 和基础 DDL(如 CREATE TABLE),触发器部分按数据库拆成 mysql_triggers.sql、pg_triggers.sql、sqlite_triggers.sql,再由部署脚本按环境选载。
实操建议:
- 用
-- @db:mysql、-- @db:pg这类注释标记区块,配合轻量解析器自动剥离(别依赖复杂 preprocessor) - 主键定义统一用
id INTEGER PRIMARY KEY AUTOINCREMENT(SQLite)→ MySQL 自动兼容,PostgreSQL 改用SERIAL即可,别用IDENTITY(10.0+ 才支持) - 时间字段统一用
TEXT存 ISO8601 字符串(如'2024-03-15T10:30:00Z'),避开TIMESTAMP WITH TIME ZONE、DATETIME、TEXT的语义差异
真正麻烦的不是语法,而是触发时机和事务边界——MySQL 在语句级提交后才触发,PostgreSQL 在事务级提交后,SQLite 在每条语句后。这点一旦涉及重试或幂等,漏掉就很难 debug。

















