不能直接跨库写目标表,必须用AFTER触发器+显式库名引用,防循环、避锁、绕开自增主键冲突;SQL Server支持同实例跨库同步(需全路径如db.schema.table),MySQL不支持跨实例写入;PostgreSQL须依赖postgres_fdw扩展实现跨库操作。

不能直接跨库写目标表,必须用AFTER触发器 + 显式库名引用,且要防循环、避锁、绕开自增主键冲突。
SQL Server 中用触发器跨库同步必须显式指定目标库名
MySQL 不支持触发器里 INSERT INTO remote_db.table,但 SQL Server 支持——前提是目标库在同一实例上,且账号有对应权限。关键不是“能不能”,而是“怎么写才不崩”。
- 目标表必须用
database_name.schema_name.table_name全路径写法,例如Cloud1.dbo.SEC_YYLeader - INSERT 时若目标表主键是
IDENTITY,必须先SET IDENTITY_INSERT Cloud1.dbo.SEC_YYLeader ON,否则报错Cannot insert explicit value for identity column - 触发器内不能用
SELECT * FROM inserted隐式列顺序匹配,必须显式列出字段:INSERT INTO Cloud1.dbo.t2 (id, name) SELECT id, user_name FROM inserted - 执行账号需同时拥有源库 SELECT 权限和目标库 INSERT/UPDATE/DELETE 权限,缺一不可
AFTER INSERT / UPDATE / DELETE 必须拆开写,不能合在一个触发器里
混写会导致逻辑混乱、inserted 或 deleted 表为空时出错,且无法精准控制同步行为。
-
AFTER INSERT:只读inserted,同步新增行;避免用INSERT IGNORE或ON DUPLICATE KEY UPDATE,它们掩盖主键冲突 -
AFTER UPDATE:对比inserted和deleted,只更新真正变化的字段,例如只改了email就别碰status -
AFTER DELETE:只读deleted,用WHERE id IN (SELECT id FROM deleted)清理目标表,注意外键级联是否已处理 - 所有触发器开头加
SET XACT_ABORT ON,确保同步失败时整个事务回滚,不残留脏数据
防循环触发和自增主键冲突是高频翻车点
同一台服务器两个库之间同步,最容易踩两个坑:一是触发器改完目标表,目标表又触发另一个触发器形成死循环;二是源表主键自增,目标表也自增,INSERT 时主键值重复或冲突。
- 禁用目标表上的所有触发器(或加
CONTEXT_INFO标记),防止它反过来触发源表逻辑 - 目标表主键不要设为
IDENTITY,改为普通INT NOT NULL,让同步语句带值写入 - 如果非要用
IDENTITY,则同步前必须SET IDENTITY_INSERT target_db.dbo.table ON,同步后立即OFF - 避免在触发器里做
SELECT COUNT(*)、JOIN 大表或调用远程存储过程——这些会拖慢事务、引发锁等待甚至超时
PostgreSQL 跨库同步得靠 postgres_fdw,不能靠原生触发器
PostgreSQL 触发器天然不支持跨库 INSERT/UPDATE,所谓“跨库同步”实际是借力外部数据包装器(postgres_fdw)。这不是语法糖,而是架构层切换。
- 先
CREATE EXTENSION postgres_fdw,再CREATE SERVER指向目标库 - 建
FOREIGN TABLE映射远端表结构,字段类型、名称、顺序必须严格一致 - 触发器函数里对
FOREIGN TABLE执行INSERT/UPDATE/DELETE,实际走的是 FDW 协议转发 - 错误如
connection to server at "x.x.x.x" failed或server "remote_server" not found,说明 FDW 配置未生效或网络不通
真正难的不是写几行 INSERT INTO ... SELECT,而是想清楚谁是源头、谁该被动响应、状态变更边界在哪——一旦把触发器当“万能同步胶水”,很快就会遇到死锁、数据不一致、事务卡住查不出原因的情况。

















