baomidou/mybatis-plus · error · RuntimeException

Batch execute failed.

Error message

Batch execute failed.

What it means

SqlHelper.executeBatch flushes JDBC batch statements and inspects each BatchResult's updateCounts. A count of Statement.EXECUTE_FAILED (-3) means the driver reports that an individual batch member failed, and mybatis-plus throws RuntimeException('Batch execute failed.'). Note the loop already treats SUCCESS_NO_INFO (-2) as ok; -3 is a genuine per-statement failure surfaced by the driver after the batch was flushed.

Source

Thrown at mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/toolkit/SqlHelper.java:226

            int row = 0;
            int size = list.size();
            int idxLimit = Math.min(batchSize, size);
            int i = 1;
            for (E element : list) {
                // 执行处理函数
                execBiFunc.apply(sqlSession, element);
                if (i == idxLimit) {
                    List<BatchResult> results = sqlSession.flushStatements();
                    for (BatchResult result : results) {
                        for (int count : result.getUpdateCounts()) {
                            if (count > 0) {
                                row += count;
                            } else if (count == Statement.SUCCESS_NO_INFO) {
                                // JDBC 返回 -2,表示执行成功但不知道影响行数
                                row++;
                            } else if (count == Statement.EXECUTE_FAILED) {
                                // JDBC 返回 -3,可根据业务决定是否抛异常
                                throw new RuntimeException("Batch execute failed.");
                            }
                        }
                    }
                    idxLimit = Math.min(idxLimit + batchSize, size);
                }
                i++;
            }
            return row;
        });
    }

    /**
     * 批量更新或保存
     *
     * @param entityClass 实体
     * @param log         日志对象
     * @param list        数据集合
     * @param batchSize   批次大小

View on GitHub (pinned to bf67d90747)

Solutions

  1. Inspect the underlying BatchUpdateException (usually chained by the sqlSession flush) for the driver's error and the failing statement index.
  2. Fix the data or the constraint conflict (dedupe input, upsert semantics via ON DUPLICATE KEY / MERGE, or pre-validate FKs).
  3. Reduce the batch size so a single failure affects a smaller unit, and make the operation transactional so it rolls back cleanly.
  4. If partial success is acceptable, chunk the batch and handle per-chunk failures rather than one large executeBatch.

Example fix

// before: raw list may contain duplicate keys -> EXECUTE_FAILED at flush
userMapper.insertBatchSomeColumn(allUsers);

// after: dedupe by natural key before batching
List<User> unique = allUsers.stream()
    .collect(Collectors.toMap(User::getEmail, Function.identity(), (a, b) -> a))
    .values().stream().collect(Collectors.toList());
userMapper.insertBatchSomeColumn(unique);
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-validate uniqueness before batching inserts
Set<Object> keys = new HashSet<>();
for (User u : batch) {
    if (!keys.add(u.getEmail())) {
        throw new IllegalArgumentException("duplicate natural key in batch: " + u.getEmail());
    }
}

Try / catch

try {
    SqlHelper.executeBatch(sqlSessionFactory, log, list, batchSize, (ss, elem) -> ss.update(...));
} catch (RuntimeException e) {
    Throwable t = e;
    while (t.getCause() != null && !(t instanceof BatchUpdateException)) t = t.getCause();
    if (t instanceof BatchUpdateException) {
        int[] counts = ((BatchUpdateException) t).getUpdateCounts();
        // identify the failing member index from counts
    }
    throw e;
}

Prevention

When it happens

Trigger: Calling saveOrUpdateBatch/deleteByIds-style batch operations (any path through SqlHelper.executeBatch) where one member statement fails at flush time: constraint violation (duplicate key, FK), data too long, or deadlocks, on drivers that continue past errors in a batch and mark counts as -3.

Common situations: Batch inserts hitting unique-key duplicates; batch updates violating FK/check constraints; MySQL rewriteBatchedStatements=true setups where a mid-batch failure marks later counts EXECUTE_FAILED; concurrent modification causing row-level conflicts in batched updates.

Related errors


AI-assisted analysis of baomidou/mybatis-plus@bf67d90747 (2026-08-14). Data as JSON: /api/errors/48ee4199cf6f586a. Report an issue: GitHub.