mysql触发器仅适用于同库轻量级强一致同步,必须用after insert获取真实自增id,禁止跨库写入,需幂等设计且不支持子事务;ddl变更会导致其静默失效。

MySQL触发器能实现同库内轻量级、强一致的数据自动同步,但仅适用于结构简单、变更频率低、容错要求不严的场景;它不是通用同步方案,不能替代基于 binlog 的 CDC 工具或主从复制。
必须用 AFTER INSERT 才能拿到真实自增 ID
主表主键为 AUTO_INCREMENT 时,BEFORE INSERT 中的 NEW.id 恒为 NULL,无法用于关联写入目标表。只有 AFTER INSERT 阶段才能安全读取已分配的真实 ID。
- 错误写法:
BEFORE INSERT中尝试INSERT INTO log_table (source_id, ...) VALUES (NEW.id, ...)——NEW.id是NULL,导致插入失败或脏数据 - 正确时机:所有依赖主键值的同步(如写日志、更新统计宽表)都必须用
AFTER INSERT - 注意批量插入:
INSERT INTO t1 SELECT ...会为每一行单独触发一次AFTER INSERT,高并发下性能敏感
UPDATE 触发器要显式判断字段变化,别无脑全量同步
直接用 OLD.* != NEW.* 做全字段比对不可靠:一旦任意字段含 NULL,整条表达式恒为 FALSE;且时间戳、更新计数器等辅助字段变动会引发大量无效同步。
- 推荐写法:
IF OLD.status != NEW.status THEN INSERT INTO status_history (...) VALUES (...); END IF; - 字符串字段加清洗:
TRIM(OLD.phone) != TRIM(NEW.phone)比裸比较更健壮 - 避免在触发器里调用函数做复杂计算——执行路径不可控,调试困难
目标表必须是本地同实例表,且需幂等设计
触发器无法跨库可靠写入。试图 INSERT INTO remote_db.t1 会报 ERROR 1418 或权限拒绝;启用 FEDERATED 引擎映射远程表虽技术可行,但稳定性差、死锁难排查、网络故障直接中断主事务。
- 安全边界:只允许写入同一 MySQL 实例下的另一张表,例如归档表、操作日志表、统计宽表
- 幂等关键:目标表至少要有联合唯一键,比如
(source_id, event_time),防止重复插入 - 锁竞争风险:目标表若被长事务占用,会拖慢源表的 DML,批量更新时尤其明显
别把触发器当消息队列用,失败即回滚,没有重试
触发器是同步阻塞执行,其 SQL 失败(如磁盘满、唯一键冲突、死锁)会导致整个原始事务回滚。这不是“同步失败”,而是“业务写入根本没成功”。
- 典型错误:
ERROR 1062 (23000): Duplicate entry或ERROR 1205 (40001): Deadlock found - 无法在触发器里用
BEGIN/COMMIT/ROLLBACK控制子事务——语法直接报错ERROR 1305 - 真正需要跨服务同步时,应切到
binlog_format = ROW+ Debezium/Kafka 链路,而非硬扛触发器
最易被忽略的一点:DDL 变更(如字段改名、类型调整、索引删除)会让触发器静默失效,且无任何告警机制;上线前必须人工校验所有关联触发器是否仍匹配新表结构。











