mysql和postgresql触发器语法不兼容,须为各数据库单独维护脚本:mysql支持多事件一行定义,postgresql要求先建returns trigger函数再绑定,且new/old访问需按tg_op显式分支,跨库同步推荐队列表+外部轮询方案。

没有“一份触发器脚本通吃所有数据库”的写法。真正的兼容靠的是拆分+隔离+显式控制,而不是语法糖堆砌。
MySQL 和 PostgreSQL 触发器不能共用同一段 CREATE TRIGGER 语句
MySQL 允许 CREATE TRIGGER ... AFTER INSERT, UPDATE, DELETE 一行定义多事件;PostgreSQL 完全不识别逗号分隔的事件列表,会直接报 syntax error near ','。SQLite 更严格,只接受单事件(AFTER INSERT 或 AFTER UPDATE 单独写)。
- 正确做法:为每个数据库单独维护触发器定义文件,比如
trigger_mysql.sql、trigger_pg.sql、trigger_sqlite.sql - MySQL 可复用同一个触发器函数体,但仍需三条
CREATE TRIGGER语句(分别绑定 INSERT/UPDATE/DELETE),避免在 5.6 等旧版本上失败 - PostgreSQL 必须先
CREATE FUNCTION log_handler() RETURNS TRIGGER,再CREATE TRIGGER ... EXECUTE FUNCTION log_handler();漏掉函数定义或返回类型不是TRIGGER,就卡在function does not exist - 别在 MySQL 触发器里写
IF TG_OP = 'INSERT'—— 这是 PostgreSQL 特有变量,MySQL 和 SQLite 都没这玩意
NEW 和 OLD 的安全访问必须按事件类型隔离
DELETE 触发器中读 NEW.id 在 PostgreSQL 和 SQLite 都会报 no such column: NEW.id,因为 NEW 在删除时为空;MySQL 虽然不报错,但值为 NULL,容易引发后续逻辑误判。
- INSERT 时只读
NEW.*,DELETE 时只读OLD.*,UPDATE 才两者都可用 - MySQL 中用
IFNULL(NEW.id, OLD.id)混用是危险的:INSERT 时OLD.id为 NULL,DELETE 时NEW.id为 NULL,结果不可控 - PostgreSQL 必须用
IF TG_OP = 'INSERT' THEN ... ELSIF TG_OP = 'UPDATE' THEN ... END IF;显式分支;MySQL 和 SQLite 靠触发器定义本身隔离事件,函数体内不该混写逻辑
SQL Server 跨库写入必须绕过隐式事务升级陷阱
直接在触发器里写 INSERT INTO [RemoteSrv].[DB].[Schema].[Table] 几乎必败:它依赖 MS DTC 自动升级为分布式事务,但默认配置下会卡在 The transaction manager has disabled its support for remote/network transactions。
- 必须提前配好链接服务器,并确保
rpc out = true和remote proc transaction promotion = true - 推荐封装远程操作为存储过程,比如目标库建
usp_sync_insert,源库触发器里调用EXEC [RemoteSrv].[TargetDB].[dbo].[usp_sync_insert] @id, @val - 字段值必须显式
CONVERT或CAST,比如CONVERT(nvarchar(50), inserted.name);隐式转换在跨库时极易静默截断或精度丢失 - 同步前务必比对两边表结构:
SELECT COLUMN_NAME, DATA_TYPE FROM [SourceDB].INFORMATION_SCHEMA.COLUMNSvs 目标库对应结果
所有数据库统一走「写本地队列表 + 外部轮询」最稳
触发器里调外部服务(HTTP、UDF、sys_exec)在 MySQL 是硬禁(报 ERROR 1422),PostgreSQL 仅支持有限异步(pg_notify),SQLite 根本没网络能力。想强行做,只会让主流程卡死或事务不一致。
- 统一建一张本地
sync_queue表,字段含table_name、row_id、op_type、payload_json(若需传多字段) - 触发器只做一件事:插入一条
sync_queue记录;由独立服务(如 Go/Python 脚本)轮询该表并执行实际同步 - 避免在触发器里做 JSON 序列化:MySQL 5.7 没原生
JSON_OBJECT,得拼字符串易出错;PostgreSQL 有row_to_json(),但 SQLite 得靠应用层补 —— 统一由轮询服务处理更可控
最容易被忽略的是字段名冲突和大小写敏感度:用 timestamp 当字段名,在 MySQL 里可能被当函数,在 PostgreSQL 里要加双引号才能用,SQLite 则完全不认。所有字段名建议避开保留字,且全程小写+下划线风格,减少跨库解析歧义。










