{"record":{"id":"48ee4199cf6f586a","repo":"baomidou/mybatis-plus","slug":"batch-execute-failed","errorCode":null,"errorMessage":"Batch execute failed.","messagePattern":"Batch execute failed\\.","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/toolkit/SqlHelper.java","lineNumber":226,"sourceCode":"            int row = 0;\n            int size = list.size();\n            int idxLimit = Math.min(batchSize, size);\n            int i = 1;\n            for (E element : list) {\n                // 执行处理函数\n                execBiFunc.apply(sqlSession, element);\n                if (i == idxLimit) {\n                    List<BatchResult> results = sqlSession.flushStatements();\n                    for (BatchResult result : results) {\n                        for (int count : result.getUpdateCounts()) {\n                            if (count > 0) {\n                                row += count;\n                            } else if (count == Statement.SUCCESS_NO_INFO) {\n                                // JDBC 返回 -2，表示执行成功但不知道影响行数\n                                row++;\n                            } else if (count == Statement.EXECUTE_FAILED) {\n                                // JDBC 返回 -3，可根据业务决定是否抛异常\n                                throw new RuntimeException(\"Batch execute failed.\");\n                            }\n                        }\n                    }\n                    idxLimit = Math.min(idxLimit + batchSize, size);\n                }\n                i++;\n            }\n            return row;\n        });\n    }\n\n    /**\n     * 批量更新或保存\n     *\n     * @param entityClass 实体\n     * @param log         日志对象\n     * @param list        数据集合\n     * @param batchSize   批次大小","sourceCodeStart":208,"sourceCodeEnd":244,"githubUrl":"https://github.com/baomidou/mybatis-plus/blob/bf67d907478c724120bf76292da54abf9e73c2b3/mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/toolkit/SqlHelper.java#L208-L244","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Inspect the underlying BatchUpdateException (usually chained by the sqlSession flush) for the driver's error and the failing statement index.","Fix the data or the constraint conflict (dedupe input, upsert semantics via ON DUPLICATE KEY / MERGE, or pre-validate FKs).","Reduce the batch size so a single failure affects a smaller unit, and make the operation transactional so it rolls back cleanly.","If partial success is acceptable, chunk the batch and handle per-chunk failures rather than one large executeBatch."],"exampleFix":"// before: raw list may contain duplicate keys -> EXECUTE_FAILED at flush\nuserMapper.insertBatchSomeColumn(allUsers);\n\n// after: dedupe by natural key before batching\nList<User> unique = allUsers.stream()\n    .collect(Collectors.toMap(User::getEmail, Function.identity(), (a, b) -> a))\n    .values().stream().collect(Collectors.toList());\nuserMapper.insertBatchSomeColumn(unique);","handlingStrategy":"try-catch","validationCode":"// pre-validate uniqueness before batching inserts\nSet<Object> keys = new HashSet<>();\nfor (User u : batch) {\n    if (!keys.add(u.getEmail())) {\n        throw new IllegalArgumentException(\"duplicate natural key in batch: \" + u.getEmail());\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    SqlHelper.executeBatch(sqlSessionFactory, log, list, batchSize, (ss, elem) -> ss.update(...));\n} catch (RuntimeException e) {\n    Throwable t = e;\n    while (t.getCause() != null && !(t instanceof BatchUpdateException)) t = t.getCause();\n    if (t instanceof BatchUpdateException) {\n        int[] counts = ((BatchUpdateException) t).getUpdateCounts();\n        // identify the failing member index from counts\n    }\n    throw e;\n}","preventionTips":["Wrap batch operations in a transaction so EXECUTE_FAILED rolls back the whole chunk.","Pre-validate constraint-relevant data (unique keys, FK targets) before batching.","Use moderate batch sizes so failures localize to a small chunk."],"tags":["batch","jdbc","constraint-violation","database"],"backgroundTag":null,"analyzedSha":"bf67d907478c724120bf76292da54abf9e73c2b3","analyzedAt":"2026-08-14T15:17:09.543Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}