触发器无法感知远程事务结果,因其仅运行在本地事务上下文中,不保证跨库操作、消息发送或外部调用的成功;真正发消息、跨库更新等必须由应用层或异步服务完成,并配合对账补偿实现最终一致性。

触发器无法感知远程事务结果
触发器运行在本地数据库事务上下文中,它只知道自己所在的那条SQL是否成功,完全不知道下游服务(比如另一个库、Kafka、HTTP接口)有没有收到或处理成功。例如,在AFTER INSERT触发器里调用INSERT INTO tx_outbox只是写本地表,不等于消息已发出——真正发消息的动作必须由外部消费者完成。如果消费者宕机或网络中断,触发器不会报错,主事务照常提交,数据“看起来成功”,实际已丢失一致性。
跨库操作被禁止且不可靠
MySQL 和 PostgreSQL 的触发器都禁止在内部执行跨库写入或显式提交/回滚:ERROR 1609 (HY000): Transaction is not allowed in stored function or trigger。有人试图用UDF或存储过程绕过限制,但这类操作既无事务保障,又难监控、易超时。更危险的是,若触发器里写了远程日志表(如INSERT INTO remote_db.audit_log),一旦网络抖动,整个主事务可能被阻塞甚至失败,而错误未必能被捕获或透出。
高并发下锁范围被意外扩大
触发器逻辑自动继承主事务的锁粒度。比如订单表的AFTER INSERT触发器去更新库存表,这个UPDATE会把库存行锁住,直到主事务结束。在分布式场景中,多个微服务可能同时操作同一张库存表,触发器带来的隐式锁会加剧争抢,拖慢TPS,甚至引发死锁。而这种锁行为在应用层代码里是看不见的,排查时容易误判为“数据库慢”或“连接池耗尽”。
binlog与复制链路干扰触发器执行
在主从架构或CDC同步场景中,sql_log_bin=0或binlog_format=STATEMENT会导致部分语句被跳过,连带触发器不执行。尤其当ORM或连接池默认关闭sql_log_bin(常见于开发环境),你写的触发器可能只在本地生效,上线后却静默失效。验证方式很简单:SELECT @@sql_log_bin;必须返回1,否则触发器根本不会被调度。
tx_outbox表,却没配对账服务;你写了pg_notify(),却没建消费组保底;你禁用了触发器做批量导入,却忘了在脚本末尾重新启用。这些细节不补全,一致性就永远悬在半空。











