我编写了一个方法insert()
,其中我尝试使用JDBC Batch将50万条记录插入到MySQL数据库中:
public void insert(int nameListId, String[] names) {
String sql = "INSERT INTO name_list_subscribers (name_list_id, name, date_added)"+
" VALUES (?, ?, NOW())";
Connection conn = null;
PreparedStatement ps = null;
try{
conn = getConnection();
ps = conn.prepareStatement(sql);
for(String s : names ){
ps.setInt(1, nameListId);
ps.setString(2, s);
ps.addBatch();
}
ps.executeBatch();
}catch(SQLException e){
throw new RuntimeException(e);
}finally{
closeDbResources(ps, null, conn);
}
}
但是每当我尝试运行此方法时,都会收到以下错误:
java.lang.OutOfMemoryError: Java heap space
com.mysql.jdbc.ServerPreparedStatement$BatchedBindValues.<init>(ServerPreparedStatement.java:72)
com.mysql.jdbc.ServerPreparedStatement.addBatch(ServerPreparedStatement.java:330)
org.apache.commons.dbcp.DelegatingPreparedStatement.addBatch(DelegatingPreparedStatement.java:171)
如果我将ps.addBatch()
替换为ps.executeUpdate()
并删除ps.executeBatch()
,它可以正常工作,但需要一些时间。如果您知道在这种情况下使用Batch是否合适,请告诉我,如果是,那么为什么它会给OurOfMemoryError
?
由于
答案 0 :(得分:43)
addBatch
和executeBatch
为您提供了执行批量插入的机制,但您仍需要自己执行批处理算法。
如果您只是将每个语句都堆放到同一个批处理中,那么就会耗尽内存。您需要每n
个记录执行/清除批处理。 n
的值取决于您,JDBC无法为您做出决定。批量大小越大,事情就越快,但是太大,你会得到内存匮乏,事情会变慢或失败。这取决于你有多少记忆。
例如,从批量大小1000开始,然后从那里尝试不同的值。
final int batchSize = 1000;
int count = 0;
for(String s : names ) {
ps.setInt(1, nameListId);
ps.setString(2, s);
ps.addBatch();
if (++count % batchSize == 0) {
ps.executeBatch();
ps.clearBatch(); //not sure if this is necessary
}
}
ps.executeBatch(); // flush the last few records.
答案 1 :(得分:5)
内存不足,因为它将所有事务保存在内存中,只在您调用executeBatch
时将其发送到数据库。
如果您不需要它是原子的并希望获得更好的性能,您可以保留一个计数器,并在每个 n 号码时拨打executeBatch
记录。