触发器不适合异步同步,因其本质是同步阻塞机制,执行时卡住主事务,网络抖动或超时会导致INSERT失败;且无法调用SYS_EXEC()或HTTP客户端,批量操作还可能不触发,故应改用binlog+CDC或Service Broker等解耦方案。

为什么触发器不适合异步同步
触发器本质是同步阻塞机制,执行时会卡住主事务,哪怕你只往消息队列发一条消息——只要网络抖动、下游不可达或超时,INSERT 就会失败。MySQL 触发器里根本不能调用 SYS_EXEC() 或 HTTP 客户端;SQL Server 里硬上链接服务器又极易触发 ERROR 7391(无法启动分布式事务)或锁等待超时。更麻烦的是,所有批量操作(LOAD DATA INFILE、INSERT INTO ... VALUES (), ()、ORM 的 bulk_create)默认不触发触发器,你以为在跑的同步逻辑,其实根本没执行。
用 Binlog + CDC 工具链替代触发器
真正能落地的异步同步,靠的是解析已提交事务的 binlog,而不是在事务内“抢跑”。这绕过了触发器的所有限制,天然支持幂等、断点续传和跨平台投递。
-
binlog_format必须设为ROW,且binlog_row_image = FULL,否则 Debezium/Canal 拿不到完整字段值 - Debezium 输出的是带 envelope 的 JSON,要用
transforms配置ExtractNewRecordState和UnwrapFromEnvelope才能得到干净数据 - Maxwell 更轻量,但不处理 DDL 变更,表结构改了得手动干预
- Kafka 消费端必须按
topic-partition-offset顺序消费,避免乱序导致状态错乱
SQL Server 用 Service Broker 解耦本地触发
如果你只能用 SQL Server 且必须从数据库出发,Service Broker 是唯一靠谱的本地解耦方案:触发器只写本地队列,激活存储过程异步转发。它不跨平台,但能防止主业务被拖死。
- 必须先执行
ALTER DATABASE YourDB SET ENABLE_BROKER WITH ROLLBACK IMMEDIATE - 触发器里不能直接
SEND,要先BEGIN DIALOG获取句柄,再SEND ON CONVERSATION - 激活过程要用
WAITFOR (RECEIVE ...)循环读取,并显式处理END CONVERSATION和错误会话 - 消息体建议用
FOR JSON PATH,别用 XML —— 解析成本高、兼容性差
应用层双写不是“替代”,而是降级兜底
当 CDC 工具链不可用(比如源库不开 binlog),才考虑应用层双写。但这不是替代触发器,而是放弃强一致性,换来的只是可控的最终一致。
- 本地写成功后,调用远程 API 失败,必须记录到
sync_task表,由后台任务轮询重试 - 每次写入要带幂等 key,比如
mysql_users_12345_20260804120300(表名+主键+时间戳) - 目标库报
Deadlock found when trying to get lock或Connection refused时,日志要捕获并降级(比如跳过本次同步,不抛异常给用户) - 绝对禁止在双写逻辑里加
SELECT ... FOR UPDATE或长事务,否则会放大锁竞争
跨平台字段映射最容易出错,比如 MySQL 的 TINYINT(1) 被当布尔,PostgreSQL 却要 BOOLEAN;datetime 精度差异也会导致写入失败。这些细节不在触发器里解决,而是在 CDC 消费端或双写服务里做显式转换。

















