2010-02-09 21 views
16

ich geschrieben habe, ein Verfahren insert(), in dem ich versuche, JDBC Batch zu verwenden, um das Einfügen eine halbe Million Datensätze in einer MySQL-Datenbank:JDBC Batch Insert OutOfMemoryError

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); 
     } 
    } 

Aber wenn ich versuche, diese Methode zu laufen, ich erhalten folgende Fehlermeldung:

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) 

Wenn ich ps.addBatch() mit ps.executeUpdate() ersetzen und entfernen ps.executeBatch(), es funktioniert gut, obwohl es einige Zeit dauert. Bitte lassen Sie es mich wissen, wenn Sie wissen, ob die Verwendung von Batch in dieser Situation angemessen ist, und wenn ja, warum gibt es OurOfMemoryError?

Dank

Antwort

40

addBatch und executeBatch geben Sie den Mechanismus zum Ausführen von Batch-Einfügungen, aber Sie müssen noch den Batch-Algorithmus selbst durchführen.

Wenn Sie einfach jede Anweisung in denselben Stapel stapeln, wie Sie es tun, wird Ihnen der Arbeitsspeicher ausgehen. Sie müssen den Stapel alle n Datensätze ausführen/löschen. Der Wert von n liegt bei Ihnen, JDBC kann diese Entscheidung nicht für Sie treffen. Je größer die Batch-Größe, desto schneller werden die Dinge, aber zu groß und Sie werden Speichermangel bekommen und die Dinge werden langsamer oder scheitern. Es hängt davon ab, wie viel Speicher Sie haben.

Beginnen Sie zum Beispiel mit einer Chargengröße von 1000 und experimentieren Sie mit verschiedenen Werten von dort.

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. 
5

Es aus der Erinnerung ist, weil es die ganze Transaktion im Speicher halten und sie nur an die Datenbank senden über, wenn Sie executeBatch nennen.

Wenn Sie es nicht brauchen Atom zu sein und möchte die bessere Leistung erhalten, können Sie einen Zähler halten und rufen executeBatch jeden n Anzahl von Datensätzen.

+0

und was sollte der Wert von n sein? – craftsman

+3

Der Wert liegt bei Ihnen. Sie müssen Ihre Anwendung vergleichen, um den bestmöglichen Wert für den Ausgleich zwischen Speicher und Leistung zu erzielen. –