不能。触发器无法可靠驱动订单状态机,因其运行在事务内,不支持跨服务调用、外部API、重试机制等状态流转必需能力;仅适合原子性高、无外部依赖的内部校验或派生字段更新,如自动填充confirmed_at或禁止非法状态跳转。

触发器能可靠驱动订单状态机吗?
不能。触发器在事务内执行,但订单状态流转常需跨服务、发通知、调外部 API 或重试失败操作——这些超出触发器能力边界。硬用 BEFORE INSERT 或 AFTER UPDATE 强制做异步动作(比如发 MQ 消息),会拖慢事务、阻塞数据库,还可能因事务回滚导致消息已发而状态未落库,产生不一致。
哪些状态变更适合用触发器兜底?
仅限原子性高、无外部依赖、失败即回滚的内部校验或派生字段更新。例如:
-
status从'draft'变为'confirmed'时,自动填充confirmed_at字段 - 当
payment_status = 'paid'且status = 'confirmed'同时成立,自动将status升级为'shipped'(注意:仅当业务规则允许“支付即发货”这一强耦合) - 禁止非法跳转:如
status从'shipped'直接回退到'draft',在BEFORE UPDATE中抛出RAISE EXCEPTION 'Invalid status transition'
这类逻辑必须写在触发器函数里,且所有判断只依赖当前行字段,不查其他表、不调函数、不写日志表。
为什么 pg_notify() 不是解药?
有人想用 PostgreSQL 的 pg_notify() 在触发器里发通知,再由监听进程处理后续动作。这看似解耦,实则埋雷:
- 通知在事务提交后才发出,但监听进程收到时,事务可能已被回滚(PostgreSQL 不保证 notify 与事务原子性绑定)
- 监听进程无法知道该通知是否对应一个最终成功的事务(比如通知发出后,主事务因锁超时失败)
- 没有重试机制:监听进程宕机期间的通知直接丢失
-
pg_notify()载荷上限 8000 字节,传不了完整订单上下文
真要解耦,得用独立的事件表 + 定时任务轮询,或者更稳妥地交给应用层基于 CDC(如 Debezium)捕获变更。
真正该由谁控制状态流转?
应用代码。状态机逻辑应集中定义在服务层,比如用 Python 的 transitions 库或 Java 的 spring-statemachine,配合数据库乐观锁(version 字段)和幂等键(order_id + event_type + event_id)来保障安全。触发器只保留最薄一层防护:字段非空校验、枚举值约束、时间戳自填充。复杂分支、超时升舱、人工干预入口、补偿流程——全都不该出现在触发器里。










