Java中PreparedStatement批量更新的核心是复用同一实例、循环调用addBatch()设参、最后executeBatch()统一执行,避免逐条执行;需分批(如每500–1000条)、开启rewriteBatchedStatements(MySQL)、手动事务控制及NULL/类型安全处理。

Java 中用 PreparedStatement 做批量更新,核心是复用预编译语句 + 批量添加参数 + 一次执行,避免重复解析 SQL 和网络往返。关键不在“怎么写”,而在“怎么组织”和“怎么调优”。
用 addBatch() + executeBatch() 组装批量操作
不要为每条记录单独执行 executeUpdate()。正确做法是:创建一个 PreparedStatement,循环设置参数后调用 addBatch(),最后统一 executeBatch()。
- SQL 模板只需写一次,如
"INSERT INTO user(name, age) VALUES (?, ?)" - 每次循环中调用
ps.setString(1, name); ps.setInt(2, age); ps.addBatch(); - 建议每 1000 条左右调用一次
executeBatch()并清空批次(ps.clearBatch()),防止内存堆积或驱动内部缓冲溢出
开启 rewriteBatchedStatements 提升 MySQL 实际性能
MySQL 驱动默认把 batch 转成多条独立语句发送,没真正优化。在 JDBC URL 中加上 ?rewriteBatchedStatements=true,驱动会自动重写为 INSERT INTO ... VALUES (...), (...), (...) 单条多值语句。
- 仅对 MySQL 有效,其他数据库(如 PostgreSQL、Oracle)靠自身驱动原生支持
- 开启后注意单条 SQL 长度限制(
max_allowed_packet),必要时拆分批次 - 不开启时,batch 仍比逐条快(减少网络往返),但远不如重写后的效果
手动分批 + 异常处理更可控
executeBatch() 抛出 BatchUpdateException,其中 getUpdateCounts() 返回每个子项的执行结果(Statement.SUCCESS_NO_INFO 或具体行数),失败位置可能中断后续执行。
立即学习“Java免费学习笔记(深入)”;
- 推荐手动分批(比如每 500 条一组),捕获异常后可记录失败批次、重试或跳过
- 避免把上万条塞进一个 batch——内存占用高、回滚代价大、定位问题困难
- 事务控制建议外层包裹:批量前
conn.setAutoCommit(false),成功后commit(),失败则rollback()
别忽略字段类型与 NULL 安全
批量更新中如果某列为 NULL,不能直接用 setString(i, null) —— 大多数驱动会报错或行为不一致。
- 统一用
setNull(i, Types.VARCHAR)(按实际类型选对应java.sql.Types常量) - 对时间类型(
DATE/TIMESTAMP),优先用LocalDateTime+setObject(i, time)(JDBC 4.2+),避免java.util.Date兼容问题 - 数值类型慎用
setObject自动推断,明确用setInt/setLong更稳定


















