Spring Boot中MongoDB@Transactional事务回滚失效问题求助
问题:Spring Boot MongoDB事务回滚未生效
问题背景
开发Spring Boot项目时,为验证@Transactional注解有效性,尝试向同一集合插入重复数据,触发E11000重复键异常后,事务回滚机制未按预期工作——第一次插入的文档仍成功写入数据库。
项目依赖
- MongoDB Server 7.0
- spring-boot-starter-parent 3.2.4
- mongodb-driver-sync 5.0
- mongodb-driver-core 5.0
MongoTransactionManager配置代码
@Configuration @EnableTransactionManagement class MongoConfig extends AbstractMongoClientConfiguration { @Value("${mongo.db}") String database; @Bean MongoTransactionManager mongoTransactionManager(MongoDatabaseFactory mongoDatabaseFactory){ MongoTransactionManager manager = new MongoTransactionManager(mongoDatabaseFactory, TransactionOptions.builder() .readPreference(ReadPreference.primary()) .readConcern(ReadConcern.LOCAL) .writeConcern(WriteConcern.MAJORITY) .build()); manager.setRollbackOnCommitFailure(true); return manager; } @Override protected String getDatabaseName() { return database; } }
插入操作代码
@Transactional public void insertMany(String collectionName, ClientSession session, List<Document> documentList, InsertManyOptions options, Boolean verbose) { if (Objects.isNull(options)){ options = new InsertManyOptions(); } long startTime = System.currentTimeMillis(); MongoCollection<Document> collection = collectionMap.get(collectionName); { collection.insertMany(documentList, options); collection.insertMany(documentList.subList(0,100), options); } long endTime = System.currentTimeMillis(); if (verbose) log.info("Collections.insertMany, collection name: {}, size: {}, Time: {}ms", collectionName, documentList.size(), (endTime - startTime)); }
问题现象
- 预期:第二次
insertMany触发E11000重复键异常时,所有插入操作回滚,数据库无新增文档 - 实际:第一次
insertMany的文档已成功写入数据库,事务未回滚 - DEBUG日志显示:已触发E11000错误,事务正常初始化并释放,但回滚未生效
- 已排查:复制模式、版本兼容性、事务启用方式均无异常
原因分析与解决方案
核心原因:操作未绑定事务会话
方法参数中传入了ClientSession,但执行insertMany时未将该会话传递给MongoDB操作方法。Spring管理的MongoDB事务会自动创建并绑定会话,但如果操作不使用这个会话,就会在事务之外执行,自然不参与回滚。
修复步骤
修改insertMany调用,将ClientSession作为参数传入MongoDB的insertMany方法:
// 修正后的插入代码 collection.insertMany(session, documentList, options); collection.insertMany(session, documentList.subList(0,100), options);
额外说明
- 确保
ClientSession是Spring事务上下文提供的会话,而非手动创建的独立会话。如果无需手动传入会话,可直接移除该参数,使用MongoTemplate或Spring Data MongoDB Repository执行操作,它们会自动绑定事务会话。 - 检查
InsertManyOptions的ordered属性(默认true):若设为false,MongoDB会继续插入不重复文档,但只要绑定了事务会话,整个操作仍会触发回滚。 - 确认MongoDB为副本集架构(单节点副本集也支持事务),这是MongoDB事务生效的前提条件。
内容的提问来源于stack exchange,提问作者junhui luo
相关产品推荐
相关产品推荐

