JDBC批处理通过rewriteBatchedStatements=true将多条INSERT合并为单条多值语句,显著减少网络往返与SQL解析次数;需配合setAutoCommit(false)、分批executeBatch()(如每500–1000条)、clearBatch()及连接池使用,实测可将百万级插入从12分钟降至50秒内。

核心是减少“单条 SQL → 网络往返 → 解析 → 执行 → 返回”这个链条的重复次数。JDBC 批处理 + MySQL 驱动的 rewriteBatchedStatements=true 参数配合使用,能把多次插入合并成一条物理语句发送,大幅压缩通信和解析开销。
批处理本身怎么写才有效
只调用 addBatch() 不执行 executeBatch() 没有意义。关键操作是“攒一批再发”,而不是每条都提交:
- 用
PreparedStatement,不是Statement;SQL 模板固定,参数动态绑定 - 循环中反复调用
pst.setXXX()和pst.addBatch(),不调用executeUpdate() - 按合理数量(如 500 或 1000 条)分批执行:
pst.executeBatch(),之后立即pst.clearBatch() - 别忘了关自动提交:
conn.setAutoCommit(false),最后显式conn.commit()
rewriteBatchedStatements=true 的作用
这个 MySQL JDBC 驱动参数不是可有可无的开关,它决定了批处理是否真正“物理合并”:
- 没开启时:JDBC 把 1000 条 insert 分成 1000 次 prepare + execute,只是减少了 Java 层的网络调用次数,数据库仍逐条解析执行
- 开启后:驱动把 1000 条
INSERT INTO t VALUES (?,?)合并为一条类似INSERT INTO t VALUES (1,'a'),(2,'b'),...,(1000,'z')的语句发给 MySQL - 效果立竿见影:网络包数量锐减、SQL 解析次数归一、InnoDB 日志写入更连续
- 连接 URL 示例:
jdbc:mysql://host/db?rewriteBatchedStatements=true&useSSL=false
配套必须做的几件事
光靠批处理和参数还不够,容易踩坑或性能打折扣:
- 连接必须复用:用连接池(如 HikariCP),避免每次新建连接的开销
- 批量大小要实测:太小(如 50)合并收益低;太大(如 10000)可能触发 MySQL 的
max_allowed_packet限制或内存压力 - 事务粒度要匹配:一个批次对应一个事务较稳妥;超大导入可分段 commit,防长事务锁表
- 避免在批处理中混用查询或 DDL:批处理只专注 INSERT/UPDATE/DELETE,其他操作单独处理
效果对比很直观
插入 100 万条简单记录(单表、3 字段):
- 单条 executeUpdate:约 8~12 分钟
- 纯 addBatch + executeBatch(未开 rewrite):约 2~3 分钟
- addBatch + rewriteBatchedStatements=true:通常压到 30~50 秒内

















