JDBC批量插入OutOfMemoryError

cra*_*man 20 jdbc large-data-volumes batch-file out-of-memory

我写了一个方法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);
        }
    }
Run Code Online (Sandbox Code Playgroud)

但每当我尝试运行此方法时,我会收到以下错误:

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)
Run Code Online (Sandbox Code Playgroud)

如果我更换ps.addBatch()ps.executeUpdate()和删除ps.executeBatch(),它工作得很好,但它需要一些时间.如果您知道在这种情况下使用Batch是否合适,请告诉我,如果是,那么为什么会给出OurOfMemoryError

谢谢

ska*_*man 44

addBatchexecuteBatch为您提供执行批量插入的机制,但您仍需要自己进行批处理算法.

如果您只是将每个语句堆叠到同一个批处理中,那么您将会耗尽内存.您需要执行/清除每个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.
Run Code Online (Sandbox Code Playgroud)


DJ.*_*DJ. 5

内存不足是因为它将所有事务保存在内存中,并且只在您调用时将其发送到数据库executeBatch.

如果你不需要它是原子的并希望获得更好的性能,你可以保留一个计数器并调用executeBatchn个记录.

  • 值取决于您,您必须对应用程序进行基准测试,以便为内存和性能之间的权衡获得最佳值. (3认同)