Java + JDBC (ODBC) 批量插入,單條提交導致 10 萬條數據即 OOM (OutOfMemoryError),DB 端處理時間極長。
| 階段 | 做法 | 結果 |
|---|---|---|
| 1. 原始 | List 循環逐條 INSERT + COMMIT | 10萬 OOM,極慢 |
| 2. 批處理 (addBatch/executeBatch) | 每 1000 條 executeBatch() + COMMIT + clearBatch() | 仍 OOM (JVM 端緩衝區積壓) |
| 3. 文件流式讀取 + 分批提交 | File.list() → ArrayList 分批 → PreparedStatement + 批處理 | 100萬條測試,**每 1 萬條提交性能最優** |
String sql = "INSERT INTO TARGET_TABLE (COL1, COL2, ...) VALUES (?, ?, ...)";
PreparedStatement ps = conn.prepareStatement(sql);
conn.setAutoCommit(false);
int batchSize = 10000; // 經測試最優
int count = 0;
while (hasNextRecord()) {
ps.setString(1, val1);
ps.setString(2, val2);
// ...
ps.addBatch();
if (++count % batchSize == 0) {
ps.executeBatch();
conn.commit();
ps.clearBatch(); // 必須清理,否則 JVM 記憶體持續增長
}
}
// 尾批提交
if (count % batchSize != 0) {
ps.executeBatch();
conn.commit();
}
ps.close();
String[] fileList = new File(uploadDir).list();
List batch = new ArrayList<>(batchSize);
for (String file : fileList) {
try (BufferedReader br = new BufferedReader(new FileReader(file))) {
String line;
while ((line = br.readLine()) != null) {
batch.add(parseLine(line));
if (batch.size() >= batchSize) {
insertBatch(batch);
batch.clear();
}
}
}
}
if (!batch.isEmpty()) insertBatch(batch);
clearBatch():JDBC 驅動內部緩衝不自動釋放conn.setAutoCommit(false),手動控制事務邊界PreparedStatement 復用执行計劃,防注入readAllLines() 類全量載入撐爆堆內存-Xmx2g -Xms2g 配合批處理更穩健CREATE TABLE ... ORGANIZATION EXTERNAL) + INSERT /*+ APPEND */ALTER SESSION ENABLE PARALLEL DML)