JDBC批量操作核心是减少网络往返与SQL解析开销,需显式调用addBatch()和executeBatch()、关闭自动提交,并为MySQL配置rewriteBatchedStatements=true才能生效。

Java 中批量数据库操作不是“多写几条 SQL”那么简单,它直接关系到性能、事务一致性、内存占用和连接稳定性。入门容易,但真正在生产环境用得稳、调得准,得踩过几处关键坑。
先搞懂 JDBC 批量操作的底层逻辑
批量操作本质是让 JDBC 驱动把多条语句打包发送给 MySQL,减少网络往返和单次解析开销。但默认情况下,JDBC 是逐条执行的——你得显式开启批处理模式。
- 调用 addBatch() 把 SQL 或参数加入批次,不是立即执行
- 调用 executeBatch() 才真正提交整批,返回每条语句影响的行数数组
- 必须关闭自动提交(connection.setAutoCommit(false)),否则每批都自动提交,失去事务控制
- 注意:MySQL 默认不支持真正的预编译批量(serverPrepStmts=false),需在连接 URL 加上 rewriteBatchedStatements=true,否则 addBatch 只是客户端拼接,效果有限
从基础写法过渡到实用模板
别一上来就套 MyBatis 批量标签,先手写标准 JDBC 批量,理解资源释放、异常回滚、分批大小这些硬约束。
- 每次批量建议控制在 500~1000 条,太大易 OOM 或锁表时间过长;太小则失去批量意义
- 务必在 finally 块或 try-with-resources 中关闭 PreparedStatement 和 Connection
- 捕获 BatchUpdateException,它能告诉你哪一条出错、错误码是多少,方便定位脏数据
- 示例场景:导入 10 万条用户数据,可按 500 条一批循环处理,失败时记录日志并跳过该批,不中断整体流程
进阶:结合连接池与框架做稳定批量
真实项目里,你不会裸写 JDBC。重点是理解框架怎么封装批量,以及如何避免常见陷阱。
立即学习“Java免费学习笔记(深入)”;
- Spring JDBC 的 JdbcTemplate.batchUpdate() 底层就是封装了 addBatch + executeBatch,但默认不开启 rewriteBatchedStatements,需在 DataSource 配置中显式设置
- MyBatis 的
标签生成 IN 语句适合小批量查询,但不适合大批量 INSERT——它会生成超长 SQL,触发 max_allowed_packet 限制 - 用 MyBatis-Plus 的 saveBatch() 时,确认它是否启用了 JDBC 批量(取决于 underlying JDBC driver 和配置),否则只是 for 循环调用单条 insert
- Druid/HikariCP 连接池要调大 maxLifetime 和 connectionTimeout,避免批量执行时间长导致连接被池误判为失效
上线前必须验证的三件事
很多批量功能本地跑得飞快,一上生产就卡死或报错,往往是因为没测对环境。
- 检查 MySQL 的 max_allowed_packet 值(默认 4MB),批量 INSERT 超长 SQL 会直接报错 “Packet too large”
- 确认事务隔离级别和锁行为:InnoDB 在可重复读下,批量 INSERT 可能触发间隙锁,阻塞其他写操作
- 监控实际执行计划:用 EXPLAIN 看批量语句是否走索引;用 SHOW PROCESSLIST 观察是否有长时间 Waiting for table metadata 锁


















