java中preparedstatement批量插入的核心是addbatch()与executebatch()配合使用,需关闭自动提交、复用预编译语句、mysql启用rewritebatchedstatements=true,并按1000条左右分批提交以平衡性能与稳定性。

Java 中用 PreparedStatement 批量插入数据,核心是开启批处理(batch)并合理设置参数,避免逐条执行 SQL 导致的网络与解析开销。关键不在“单个 PreparedStatement 多次 set + execute”,而在于 addBatch() + executeBatch() 的组合使用。
启用批处理并分批提交
数据库驱动和 JDBC 协议支持批量操作,但需显式调用 addBatch() 累积语句,再统一执行。不调用 executeBatch(),所有 addBatch() 都不会真正发送到数据库。
- 每次
addBatch()只是把当前参数绑定后的 SQL 加入本地缓冲区,不触发网络请求 - 调用
executeBatch()才一次性发送多条语句(具体是否合并为单个网络包取决于驱动和数据库配置) - 建议按固定大小分批(如 1000 条/批),防止内存溢出或事务过大回滚慢
关闭自动提交并手动控制事务
默认 auto-commit 模式下,每批执行都会隐式提交,极大降低性能。应提前 connection.setAutoCommit(false),在全部批次成功后统一 commit(),失败时 rollback()。
- 避免每批都刷盘、写日志、释放锁,显著提升吞吐量
- 注意连接超时和事务持有时间,长时间未提交可能被数据库 kill 或阻塞其他操作
- 生产环境建议配合 try-with-resources 和 finally 块确保 commit/rollback 被执行
预编译 SQL + 参数绑定要一次到位
SQL 模板必须在循环外创建一次 PreparedStatement,并在循环内仅做 setXXX() 和 addBatch();重复 new PreparedStatement 会失去预编译优势,甚至引发句柄泄漏。
- 错误写法:
for (...) { ps = conn.prepareStatement(sql); ps.setString(...); ps.addBatch(); } - 正确写法:
ps = conn.prepareStatement(sql); for (...) { ps.setString(...); ps.addBatch(); if (i % 1000 == 0) ps.executeBatch(); } - MySQL 需额外加参数
rewriteBatchedStatements=true(如jdbc:mysql://...?rewriteBatchedStatements=true)才能将多条 INSERT 合并为INSERT INTO t VALUES (...), (...), (...),否则仍是多条独立语句
处理 executeBatch 的返回值与异常
executeBatch() 返回 int[],每个元素对应一条语句影响的行数(通常为 1)。若某条失败,不同数据库行为不同:有的全批失败抛 BatchUpdateException,有的继续执行(需检查 getUpdateCounts() 中的 EXECUTE_FAILED 标记)。
- 捕获
BatchUpdateException,用e.getUpdateCounts()分析哪些位置失败 - 不要假设返回数组长度一定等于 addBatch 次数——部分驱动在出错时可能截断
- 对强一致性场景,可考虑失败后清空 batch 并逐条重试,记录失败 ID 便于补偿
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











