Axon Saga执行信息持久化疑问:服务宕机时存储表数据为空如何处理
核心问题解答
1. READ_UNCOMMITTED隔离级别下的额外注意事项
除脏读问题外,还有三类需要重点关注的风险:
- 幻读/不可重复读异常:未提交的Saga记录如果触发回滚,负责故障恢复的并发查询线程会出现「之前能查到记录、二次查询时记录消失」的异常,直接导致恢复逻辑执行失败
- 死锁概率提升:长事务持有数据库行锁/表锁的时间远高于短事务,高并发场景下极易和其他业务写操作出现锁等待甚至死锁
- 跨域一致性风险:如果Saga步骤同时修改业务库数据,该业务数据和Saga记录同属一个未提交事务,一旦异常回滚会出现业务实际执行状态和Saga记录状态不一致的问题
2. 不开启READ_UNCOMMITTED的持久化方案
Axon官方提供了两种合规方案满足强一致持久化要求:
- 事务边界拆分:给每个
@SagaEventHandler方法添加@Transactional(propagation = Propagation.REQUIRES_NEW)注解,将每一步Saga事件处理逻辑设置为独立事务,执行完成后自动提交,不需要等待全流程结束 - 替换Saga存储实现:直接更换为Axon原生的JDBC Saga存储组件,它默认会在每步Saga状态变更后独立提交事务,完全不依赖
AbstractUnitOfWork的全局统一提交逻辑
3. Axon长事务设计考量与调整方案
Axon默认采用全流程长事务的设计,核心是保证Saga状态变更、业务事件发送、业务数据修改的原子性,避免出现「Saga状态更新了但后续事件没发出」或者「事件发出去了但Saga状态没更新」的中间不一致状态。
如果要调整为每步提交,可以通过两种配置实现:
- 基础配置调整:在Axon配置文件中设置
axon.saga.jpa.use-explicit-flush=true,同时给所有Saga事件处理方法添加独立事务注解即可 - 自定义事务逻辑:重写
UnitOfWork的事务提交钩子,在每个Saga事件处理完成后主动触发事务提交,而非等待全流程结束
现有实现优化建议
你们当前的调整方案可以做两处优化,避免潜在风险:
- 关于未使用
@EndSaga注解的问题:通过SagaLifecycle.end()结束Saga流程是完全符合Axon规范的,和@EndSaga注解效果一致,不是导致数据未持久化的原因,不需要额外调整 - 自定义
JpaSagaStore强制开启本地事务的注意事项:- 本地事务要和业务操作的事务做隔离,避免出现业务操作回滚但Saga状态已经提交的不一致问题
- 插入/更新Saga记录后要主动调用
entityManager.flush(),保证数据确实写入数据库后再提交事务,避免出现事务提交了但数据还在缓冲区未写入磁盘的情况 - 删除逻辑不需要修改,依然保留全流程补偿完成后再删除记录的原有逻辑即可
内容的提问来源于stack exchange,提问作者RLS
相关产品推荐
相关产品推荐

