能用但别默认选它;同步逻辑越简单单向越可靠,双向或聚合时应改用应用层或物化视图;必须绕开UPDATE_DATA_SOURCE字段防循环,设为默认值+NOT NULL;优先用AFTER触发器做校验和同步。

直接说结论:能用,但别默认选它;同步逻辑越简单、越单向,触发器越可靠;一旦涉及双向更新或聚合计算,立刻考虑应用层或物化视图替代。
触发器同步必须绕开 UPDATE_DATA_SOURCE 这类标记字段
双向同步(A 表改 → B 表同步,B 表改 → A 表同步)天然容易循环。案例里用 UPDATE_DATA_SOURCE 字段拦截“自己人改的”操作,是有效手段,但容易漏判或被绕过。
- 所有写入路径(包括批量导入、ETL 工具、DBA 直连)都必须遵守该字段约定,否则触发器会误触发
-
UPDATE_DATA_SOURCE = 0必须作为业务写入的默认值,不能靠应用层“记得设”,而应设为列默认值 + NOT NULL 约束 - Oracle/PostgreSQL 中用
WHEN子句过滤比在 BEGIN 内 IF 判断更早生效,性能略优
AFTER 触发器比 BEFORE 更适合一致性校验
想让 B 表字段严格等于 A 表某字段值?别在 BEFORE UPDATE 里偷偷改 NEW.b_value —— 这会让原始 SQL 的语义失真,调试时查不到真实意图。
- 用
AFTER UPDATE读取inserted(SQL Server)或NEW(PostgreSQL/MySQL),再执行UPDATE同步目标表 - 聚合类同步(如统计行数)必须加
SELECT ... FOR UPDATE锁主记录,否则并发更新会导致结果错乱 - 校验失败时用
RAISE EXCEPTION(PG)或THROW(SQL Server)中断事务,别用UPDATE静默覆盖——掩盖问题比修复问题更危险
INSERT/UPDATE/DELETE 要分开写触发器,别塞进一个
同一个触发器处理三种 DML 类型,代码易混、逻辑难测、出错难定位。比如 DELETED 表在 INSERT 时为空,INSERTED 在 DELETE 时为空,混写容易 NPE 式报错。
-
AFTER INSERT:只读INSERTED,同步新增记录 -
AFTER UPDATE:对比INSERTED和DELETED,只同步真正变化的字段(如只改了name,就别碰email) -
AFTER DELETE:只读DELETED,清理关联数据(注意外键级联可能已做这事,重复触发反而出错)
触发器里别做跨库、远程调用或复杂计算
触发器运行在事务上下文中,任何阻塞、超时、网络异常都会拖垮整个事务。哪怕只是调一次 HTTP 接口,也极大概率导致锁等待或死锁。
- 禁止在触发器内执行
INSERT INTO remote_db.table或调用curl类扩展函数 - 避免在触发器里跑
SELECT COUNT(*) FROM huge_table—— 这类聚合应提前物化或由定时任务刷新 - 高频小表(如日志、点击流)同步优先走应用层消息队列,触发器只用于低频、强一致核心业务(如订单-库存)
真正麻烦的不是写触发器,而是当它开始慢、开始报错、开始和另一个触发器打架时,你得在不中断业务的前提下临时关掉它——所以每个触发器开头必须带开关判断,比如 IF NOT EXISTS (SELECT 1 FROM config WHERE key = 'sync_user_to_copy' AND value = 'on'),而且这个 config 表得支持秒级生效。

















