You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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);

额外说明

  1. 确保ClientSession是Spring事务上下文提供的会话,而非手动创建的独立会话。如果无需手动传入会话,可直接移除该参数,使用MongoTemplate或Spring Data MongoDB Repository执行操作,它们会自动绑定事务会话。
  2. 检查InsertManyOptions的ordered属性(默认true):若设为false,MongoDB会继续插入不重复文档,但只要绑定了事务会话,整个操作仍会触发回滚。
  3. 确认MongoDB为副本集架构(单节点副本集也支持事务),这是MongoDB事务生效的前提条件。

内容的提问来源于stack exchange,提问作者junhui luo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 17:56:24