必须显式捕获BatchUpdateException,因其getUpdateCounts()返回含Statement.EXECUTE_FAILED(-3)的数组,可精确定位失败语句;若仅用Exception捕获将丢失该关键信息。

在 Java 中使用 JDBC 批量更新(addBatch() + executeBatch())时,若某条 SQL 执行失败(如主键冲突、字段超长、约束不满足等),JDBC 驱动通常会抛出 BatchUpdateException。捕获并正确处理它,是保障批量操作健壮性的关键。
为什么 BatchUpdateException 不能用普通 Exception 捕获?
BatchUpdateException 是 SQLException 的子类,但它的行为有特殊性:
- 它可能包含部分成功信息(即哪些语句执行成功了);
- 它的
getUpdateCounts()返回的是int[],其中成功项为影响行数,失败项为Statement.EXECUTE_FAILED(值为 -3); - 普通
catch (Exception e)虽能捕获,但会丢失其特有方法(如getUpdateCounts()),无法做精细化错误定位。
正确捕获和解析 BatchUpdateException
必须显式 catch (BatchUpdateException e),并结合 getUpdateCounts() 和原始异常链分析失败点:
BatchUpdateException
-
MySQL(默认):遇到第一条失败语句即停止执行,后续语句不执行,
getUpdateCounts()中失败项及之后全为-3; -
PostgreSQL:默认开启“全部执行”,即使某条失败,其余仍尝试执行,
getUpdateCounts()可准确反映每条结果; -
Oracle:需启用
setExecuteBatch(true)或使用OraclePreparedStatement,否则可能不抛BatchUpdateException; - 可通过
Connection#setAutoCommit(false)+ 手动rollback()控制事务粒度,避免部分成功导致数据不一致。
实用建议:增强批量更新的容错能力
仅捕获异常还不够,生产环境推荐以下做法:
- 对批量数据做预校验(如检查主键是否已存在、长度是否超限),减少 DB 层报错;
- 将大批次拆分为小批次(如每 100 条一批),降低单次失败影响范围;
- 记录失败语句的原始参数(如日志中打印
"INSERT INTO user(name) VALUES ('Charlie')"),便于排查; - 考虑使用 MyBatis 或 JdbcTemplate 等框架,它们对批量异常做了封装(如 MyBatis 的
BatchExecutor会抛BatchExecutorException,内部仍基于BatchUpdateException)。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











