24

我编写了一个方法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

谢谢

4

2 回答 2

48

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.
于 2010-02-09T08:34:51.873 回答
6

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

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

于 2010-02-09T08:18:00.113 回答