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

Quarkus中用事务批量执行insertMany时MongoDB报WriteConflict错误

问题分析与解决方案

核心问题原因

  • 超大事务引发锁竞争:你将100万条数据的插入操作放在单个事务中执行,MongoDB的事务机制并不适合承载这种大规模批量操作。长时间运行的事务会持续占用锁资源,随着数据量累积到80万条后,锁竞争加剧,WriteConflict错误的触发概率会急剧上升。
  • 批量插入逻辑失效:代码中每次循环都新建ArrayList并仅添加单个元素,i == sampleDataList.size()这个条件几乎不会生效(仅i=1时触发),实际相当于每次只插入1条数据,完全浪费了insertMany的批量优势,还让事务内的操作数暴增,进一步放大了冲突风险。

修正后的代码实现

int totalCount = 1000000;
int batchSize = 100000;
// 提前初始化对应容量的列表,避免频繁扩容
ArrayList<SampleData> sampleDataList = new ArrayList<>(batchSize);

for (int i = 1; i <= totalCount; i++) {
    sampleDataList.add(new SampleData(i));
    
    // 达到批量阈值或处理到最后一批时执行插入
    if (i % batchSize == 0 || i == totalCount) {
        // 每批数据使用独立事务,避免单个事务过大
        try (ClientSession clientSession = mongoClient.startSession()) {
            clientSession.startTransaction();
            try {
                sampleDataRepo.mongoCollection().insertMany(clientSession, sampleDataList);
                clientSession.commitTransaction();
            } catch (WriteConflictException e) {
                // 遇到冲突时重试当前批次
                clientSession.abortTransaction();
                // 重置循环索引,重新处理当前批次数据
                i -= sampleDataList.size();
            } catch (Exception e) {
                clientSession.abortTransaction();
                throw new RuntimeException("数据插入失败: " + e.getMessage(), e);
            }
        }
        sampleDataList.clear();
    }
}

关键优化说明

  • 拆分事务:每批数据使用独立事务提交,避免单个事务承载百万级操作,大幅降低锁竞争和WriteConflict的触发概率。
  • 修复批量逻辑:预先初始化对应容量的列表,累积到指定批量大小再执行插入,充分发挥insertMany的性能优势。
  • 冲突重试处理:针对WriteConflictException单独做重试逻辑,保证当前批次数据最终能插入成功。
  • 资源自动管理:使用try-with-resources自动关闭ClientSession,避免会话资源泄漏。

内容的提问来源于stack exchange,提问作者Zhen Wei

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 20:45:38