java jdbc批处理需预编译复用、事务控制、驱动适配、参数调优四者协同;须复用preparedstatement、按数据库配置驱动参数、合理设批大小并手动管理事务、执行后校验返回值。

Java JDBC 批处理不是“堆一堆 addBatch 就完事”,而是预编译复用、事务控制、驱动适配、参数调优四者协同的结果。用错一个环节,万级插入可能比单条还慢。
必须复用 PreparedStatement,禁止循环中反复创建
每次 new PreparedStatement 都会触发 SQL 解析、执行计划生成和资源分配,完全抵消批处理收益。正确做法是:SQL 模板在循环外 prepare,循环内只 set 参数 + addBatch。
- ✅ 正确:PreparedStatement ps = conn.prepareStatement("INSERT INTO t(a,b) VALUES (?,?)"); for (User u : list) { ps.setString(1, u.getName()); ps.setInt(2, u.getAge()); ps.addBatch(); }
- ❌ 错误:for (User u : list) { PreparedStatement ps = conn.prepareStatement("..."); ps.setString(...); ps.addBatch(); }
按数据库类型启用关键驱动优化参数
不同数据库的批量机制底层差异极大,驱动配置不到位,addBatch 就是假批量。
-
MySQL:URL 必须加 rewriteBatchedStatements=true(如
jdbc:mysql://x/x?rewriteBatchedStatements=true),且useServerPrepStmts=false;否则每条仍发独立 INSERT -
Oracle 12c+:必须用 ojdbc8.jar 或 ojdbc11.jar,验证方式:
System.out.println(oracle.jdbc.driver.OracleDriver.getMajorVersion())输出 8 或 11;ojdbc6 及更早版本仅客户端模拟,无效 -
SQL Server:推荐配合表值参数(TVP)或开启
sendStringParametersAsUnicode=false减少字符转换开销
合理设置批大小并手动控制事务边界
批太小,网络往返多;批太大,内存溢出或 PGA 耗尽(Oracle)/锁等待加剧(MySQL)。不能依赖 executeBatch 自动提交。
- MySQL 建议每批 500–2000 行,每 1000–5000 行 commit 一次
- Oracle 建议每批 1000–5000 行,含 CLOB/BLOB 时下调至 1000;必须
conn.setAutoCommit(false),executeBatch 后显式commit() - 每次 executeBatch() 后调用
ps.clearBatch(),循环末尾别忘处理剩余数据
务必检查 executeBatch 返回值,避免静默失败
Oracle 和多数驱动默认 all-or-nothing,但 JDBC 层不抛异常,只返回 int[] 数组,其中 Statement.EXECUTE_FAILED 表示某条失败。漏判等于数据丢失。
- 执行后立即遍历结果:
int[] result = ps.executeBatch(); for (int i = 0; i - 对 insert 场景,可加
ps.setFetchSize(0)避免驱动额外拉取元数据,提升效率
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











