使用 preparedstatement 执行批量数据提升的核心做法是:先通过 addbatch() 将多条 sql 参数化语句加入队列,再调用 executebatch() 一次性提交给数据库。这样做能显著减少网络往返次数并降低解析开销。若需确保事务安全或处理大量数据,应配合手动事务管理(关闭自动提交)并按批次大小进行拆分。

如何正确配置 PreparedStatement 以启用批量功能
要让 JDBC 驱动真正支持批量操作,必须在建立连接时配置 URL 参数,并在代码中显式调用 addBatch() 和 executeBatch()。默认情况下,某些驱动可能不会优化批量执行,因此需要明确指示。

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
public class BatchExample {
public static void main(String[] args) {
String url = "jdbc:mysql://localhost:3306/test?rewriteBatchedStatements=true";
try (Connection conn = DriverManager.getConnection(url, "user", "pass");
PreparedStatement pstmt = conn.prepareStatement("INSERT INTO users (name, age) VALUES (?, ?)")) {
// 模拟批量数据
for (int i = 0; i < 1000; i++) {
pstmt.setString(1, "User_" + i);
pstmt.setInt(2, 20 + (i % 5));
pstmt.addBatch();
}
// 执行批量
int[] results = pstmt.executeBatch();
System.out.println("Inserted rows: " + results.length);
} catch (Exception e) {
e.printStackTrace();
}
}
}上述代码中,URL 里的 rewriteBatchedStatements=true 是关键。对于 MySQL 驱动,这会将多个 INSERT 合并为一条多值 SQL 语句发送。如果不加此参数,驱动可能会逐条发送,失去批量优势。addBatch() 将当前参数集加入队列,executeBatch() 触发实际执行并返回每个语句影响的行数数组。
立即学习“Java免费学习笔记(深入)”;
如何处理大批量数据以避免内存溢出
当数据量极大时,将所有数据放入一个批次会导致 PreparedStatement 内部缓冲区溢出或内存不足。解决方案是按固定数量(如 500 或 1000 条)分批执行,并在每批结束后清空批次或重新创建语句对象。

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
public class LargeBatchExample {
public static void main(String[] args) {
String url = "jdbc:mysql://localhost:3306/test?rewriteBatchedStatements=true";
int batchSize = 500;
int totalRecords = 10000;
try (Connection conn = DriverManager.getConnection(url, "user", "pass");
PreparedStatement pstmt = conn.prepareStatement("INSERT INTO users (name, age) VALUES (?, ?)")) {
for (int i = 0; i < totalRecords; i++) {
pstmt.setString(1, "User_" + i);
pstmt.setInt(2, 20 + (i % 5));
pstmt.addBatch();
if ((i + 1) % batchSize == 0) {
pstmt.executeBatch();
pstmt.clearBatch(); // 清空已执行的批次
}
}
// 处理剩余不足一批的数据
if (totalRecords % batchSize != 0) {
pstmt.executeBatch();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}该示例展示了分块策略。每积累 batchSize 条记录就执行一次 executeBatch() 并调用 clearBatch()。这确保了内存中只保留少量待发送数据,避免 OOM。同时,由于复用了同一个 PreparedStatement 对象,避免了频繁编译 SQL 的开销。注意,clearBatch() 仅清除批次队列,不关闭连接或语句。
在批量插入中如何处理主键冲突或重复数据
在批量插入场景下,如果目标表有唯一约束(如主键或唯一索引),遇到重复数据会抛出异常并中断整个批次。为避免单条失败导致全部回滚,可以使用 ON DUPLICATE KEY UPDATE(MySQL)或 MERGE INTO(Oracle/SQL Server)等语法,或在应用层预先过滤重复项。
例如,修改 SQL 为:INSERT INTO users (id, name, age) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE name=VALUES(name), age=VALUES(age)。这样即使 ID 重复,也会更新现有记录而非报错。若使用其他数据库,需替换为对应语法。此外,也可在插入前查询是否存在,但会增加额外查询开销,通常不如直接利用数据库幂等语句高效。


















