在業務系統中,數據導入、日誌落地、報表生成等場景常面臨「單次寫入 10 萬甚至百萬條記錄」的需求。若逐條執行 INSERT,網絡往返(RTT)與數據庫解析開銷會拖垮性能。JDBC 提供的 addBatch() / executeBatch() 是標準解法,但預設配置下效率往往不盡如人意。
核心步驟:關閉自動提交 → 累積批次 → 一次性執行 → 手動提交。
public class MysqlBatchUtil {
private static final String SQL = "INSERT INTO db_test (param1,param2,param3,param4,param5) VALUES (?,?,?,?,?)";
private static final String URL = "jdbc:mysql://localhost:3306/test";
private static final String USER = "root";
private static final String PASS = "123456";
public void doStore() throws Exception {
Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection(URL, USER, PASS);
conn.setAutoCommit(false); // 關鍵:關閉自動提交
PreparedStatement psts = conn.prepareStatement(SQL);
long start = System.currentTimeMillis();
for (int i = 0; i <= 100_000; i++) {
psts.setString(1, i + "param1");
psts.setString(2, i + "param2");
psts.setString(3, i + "param3");
psts.setString(4, i + "param4");
psts.setString(5, i + "param5");
psts.addBatch();
}
psts.executeBatch(); // 一次性發送
conn.commit(); // 手動提交事務
conn.close();
System.out.println("耗時: " + (System.currentTimeMillis() - start) + " ms");
}
}
測試結果:100,001 條,**4725 ms**(約 4.7 秒)。雖比單條插入快數十倍,但離「高性能」尚有差距。
MySQL JDBC 驅動預設不會真正將批次合併為單條 SQL,而是仍逐條發送。需在連接字串開啟兩個關鍵參數:
rewriteBatchedStatements=true:核心開關,驅動會將多條 INSERT INTO t VALUES (?,?) 重寫為 INSERT INTO t VALUES (?,?),(?,?)... 形式,單次網絡交互完成所有寫入。useServerPrepStmts=false:禁用服務端預編譯,改用客戶端拼裝 SQL,配合重寫機制效果最佳。// 只需修改連接字串 String optimizedUrl = URL + "?useServerPrepStmts=false&rewriteBatchedStatements=true"; Connection conn = DriverManager.getConnection(optimizedUrl, USER, PASS); // 其餘代碼完全不變...
測試結果:同樣 100,001 條,**1213 ms**(約 1.2 秒)。性能提升近 4 倍!
| 參數 | 預設值 | 作用機制 | 性能影響 |
|---|---|---|---|
| rewriteBatchedStatements | false | 驅動層將 Batch 合併為多值 INSERT 語句 | 網絡包數從 N 降為 1,消除 RTT 開銷 |
| useServerPrepStmts | true | true 時使用服務端 PreparedStatement,無法重寫;false 時客戶端拼裝 | 必須配合 false 才能觸發重寫邏輯 |
executeBatch() 建議 500~5000 條,避免 SQL 過大超過 max_allowed_packet 或導致 OOM。executeBatch() + commit(),平衡事務日誌與鎖持有時間。setInt、setLong 等原生類型,減少字符串轉換開銷。maximumPoolSize 與 connectionTimeout。JDBC 批次插入的性能天花板,往往不在代碼邏輯,而在於驅動層面的網絡交互優化。只要加上 rewriteBatchedStatements=true&useServerPrepStmts=false,即可讓 MySQL 驅動釋放真實性能。配合合理的批次大小、事務控制與索引策略,百萬級數據導入輕松進入「秒級」俱樂部。