使用多Repository时MongoDB响应式事务不生效问题排查
问题原因及解决方案
核心问题分析
subscribe()调用脱离事务上下文
你直接调用firstRepository.save().subscribe()会立即触发数据库操作,完全脱离了@Transactional管理的反应式事务上下文。反应式事务依赖ReactiveTransactionContext在Mono/Flux的链式调用中传播,一旦手动调用subscribe(),操作会在独立线程执行,不受当前事务约束。同步异常无法触发反应式事务回滚
直接抛出RuntimeException这类同步异常,无法被反应式事务上下文感知。反应式方法的异常必须通过Mono.error()包装,事务管理器才能捕获异常并执行回滚逻辑。操作未形成反应式链式调用
两个保存操作没有通过Mono/Flux的链式方法(如flatMap)串联,导致第一个保存操作独立于事务边界之外,不受事务控制。
修正后的代码示例
ApiService修正版
@Service @RequiredArgsConstructor public class ApiService { private final FirstRepository firstRepository; private final SecondRepository secondRepository; @Transactional public Mono<SecondDocument> save(FirstDocument firstDocument, SecondDocument secondDocument) { return firstRepository.save(firstDocument) .flatMap(savedFirst -> { // 模拟异常,用Mono.error抛出 return Mono.error(new RuntimeException("test")); // 正常流程执行第二个保存 // return secondRepository.save(secondDocument); }); } }
关键修正点
- 移除
subscribe()调用,用flatMap串联操作,确保所有数据库操作处于同一事务上下文。 - 用
Mono.error()抛出异常,让反应式事务管理器捕获并触发回滚。 - 所有操作通过反应式链式调用串联,保证事务覆盖完整操作流程。
额外注意事项
- 确认MongoDB集群支持事务:你使用的Atlas 6.0.11版本满足要求,但需保证连接字符串中的副本集配置正确。
- 配置类中
@EnableTransactionManagement已正确开启,无需修改。 - 调用该方法时需通过反应式方式订阅(如Controller返回Mono由Spring Web自动订阅),禁止在方法内部手动调用
subscribe()。
内容的提问来源于stack exchange,提问作者zellcorp
相关产品推荐
相关产品推荐

