提交之后再发消息,用 @TransactionalEventListener 够不够?回滚时普通事件监听器会怎样?忘了加 @Transactional 会怎样?AFTER_COMMIT 里发送失败消息就丢了吗?发件箱怎么保证至少一次?这篇在 Spring Boot 4.0.8 和 MySQL 上逐项实测。
普通 @EventListener 立刻执行(此时事务还没结束):o1 BEFORE_COMMIT 监听器:o1 AFTER_COMMIT 监听器:o1,尝试发送到 broker AFTER_COMMIT 监听器:o1 已发送 AFTER_COMPLETION 监听器:o1 fallbackExecution=true 的监听器:o1(没有事务时也执行) orders 里有 o1:1 行;broker 收到:[o1]
普通监听器立刻执行;BEFORE_COMMIT → 提交 → AFTER_COMMIT → AFTER_COMPLETION。
普通 @EventListener 立刻执行(此时事务还没结束):o2 AFTER_ROLLBACK 监听器:o2 AFTER_COMPLETION 监听器:o2 调用方捕获:业务异常,回滚 orders 里有 o2:0 行;broker 收到:[o1]
普通监听器副作用已发生;AFTER_COMMIT 不执行。
fallbackExecution=true 的监听器:o3(没有事务时也执行) 普通 @EventListener 立刻执行(此时事务还没结束):o3 orders 里有 o3:1 行;broker 收到:[o1]
默认静默忽略,fallbackExecution 才执行。
普通 @EventListener 立刻执行(此时事务还没结束):o4 BEFORE_COMMIT 监听器:o4 AFTER_COMMIT 监听器:o4,尝试发送到 broker AFTER_COMPLETION 监听器:o4 fallbackExecution=true 的监听器:o4(没有事务时也执行) place(o4) 正常返回,调用方没有收到任何异常 orders 里有 o4:1 行;broker 收到:[o1](o4 没有发出去,也没有任何补偿)
订单已提交消息丢失,没有补偿。
AFTER_COMMIT 里直接用 JdbcTemplate 写了 audit 行 a1(没有 REQUIRES_NEW)
AFTER_COMMIT 里在 REQUIRES_NEW 事务里写了 audit 行 a2
audit 表里的行:[{id=a1, note=same-tx}, {id=a2, note=new-tx}]文档要求 REQUIRES_NEW;我的 JDBC 环境里碰巧也保存了。
orders 和 outbox 各新增了 p1、p2;outbox 未发送行数 2 relay:发送 p1 失败(broker 不可用),保留在 outbox relay:发送 p2 失败(broker 不可用),保留在 outbox broker 不可用时 relay 发送了 0 条;outbox 未发送行数 2 broker 恢复后 relay 发送了 2 条;outbox 未发送行数 0;broker 收到:[p1, p2] relay:发送 p3 成功,但在标记 sent 之前崩溃了 模拟 relay 在发送后、标记前崩溃;broker 收到 [p3],outbox 未发送行数 1 relay 重启后再发送一轮;broker 一共收到 [p3, p3](p3 收到了 2 次)
同事务写 outbox,relay 补发;至少一次,可能重复。