MongoDB事务回滚需同时满足:4.0+副本集/分片集群、正确配置MongoTransactionManager、public方法抛出未捕获RuntimeException;缺一不可,否则@Transactional无效。

Spring Boot + MongoDB 的事务回滚不会自动生效,除非你同时满足:MongoDB 4.0+ 副本集/分片集群、正确配置 MongoTransactionManager、方法为 public 且抛出未捕获的 RuntimeException(或显式声明 rollbackFor)。
为什么 @Transactional 在 MongoDB 中经常不回滚?
根本原因不是注解写错了,而是底层机制和关系型数据库完全不同:
- MongoDB 事务依赖客户端 session,
MongoTransactionManager必须接管这个 session 生命周期;若没配或配错,@Transactional就只是个“装饰” - Spring Data MongoDB 默认使用
SimpleMongoClientDatabaseFactory,它不支持事务——必须手动替换为支持事务的MongoDatabaseFactory实现(如SimpleMongoClientDatabaseFactory的子类或ReactiveMongoDatabaseFactory不适用) - 事务只对同一
MongoDatabase下的操作有效;跨库、跨 replica set 成员写入会直接报错,根本进不了回滚逻辑 - 事务块内调用非
@Transactional的 DAO 方法(比如直接用MongoTemplate而非 repository),该操作游离于事务之外
必须配置的三项核心组件
缺一不可,顺序不能乱:
- 在
application.properties中启用副本集连接(单机模式不支持多文档事务):spring.data.mongodb.uri=mongodb://localhost:27017/mydb?replicaSet=rs0 - 定义
MongoTransactionManagerBean,绑定到你的MongoClient和数据库名:@Bean<br>public MongoTransactionManager transactionManager(MongoDatabaseFactory dbFactory) {<br> return new MongoTransactionManager(dbFactory);<br>} - 确保所有涉及事务的数据访问都通过同一个
MongoRepository或带事务上下文的MongoTemplate(需注入TransactionSynchronizationManager管理的 session)
@Transactional 方法里 catch 了异常却不回滚?
这是最常被忽略的陷阱:一旦你在方法体内用 try-catch 吞掉异常,Spring 就收不到 rollback 信号。
- 错误写法:
try {<br> repo.save(user);<br> throw new RuntimeException("模拟失败");<br>} catch (Exception e) {<br> log.error(e.getMessage());<br> // 没 re-throw,也没手动 setRollbackOnly → 事务提交!<br>} - 正确做法二选一:
– 直接抛出:throw new RuntimeException("xxx");
– 或手动标记回滚:TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); - 注意:
setRollbackOnly()只在当前事务活跃时有效;如果事务已提交/未开启,会抛NoTransactionException
回滚失败时先查这三件事
别急着改代码,先确认基础是否成立:
- 运行
db.runCommand({ replSetGetStatus: 1 }),确认 MongoDB 是副本集模式且状态为PRIMARY或SECONDARY - 检查日志里有没有
Transaction numbers are only allowed on a replica set member or a sharded cluster类似报错 - 在事务方法入口加断点,验证
TransactionSynchronizationManager.isActualTransactionActive()返回true—— 如果是false,说明事务管理器根本没生效
事务不是开关,而是一条链:从连接串 → MongoTransactionManager → 方法签名 → 异常传播路径,任一环断裂,回滚就静默失效。最容易被跳过的其实是副本集配置和事务管理器 Bean 的注册时机。


















