2010-02-09 38 views
16

Tôi đã viết một phương pháp insert() trong đó tôi đang cố gắng sử dụng JDBC hàng loạt cho chèn nửa triệu bản ghi vào cơ sở dữ liệu MySQL:hàng loạt JDBC Chèn 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); 
     } 
    } 

Nhưng bất cứ khi nào tôi cố gắng chạy phương pháp này, tôi nhận được lỗi sau:

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) 

Nếu tôi thay ps.addBatch() với ps.executeUpdate() và loại bỏ ps.executeBatch(), nó hoạt động tốt, mặc dù phải mất một thời gian. Xin vui lòng cho tôi biết nếu bạn biết nếu sử dụng hàng loạt là thích hợp trong tình huống này, và nếu có, thì tại sao nó cung cấp cho OurOfMemoryError?

Cảm ơn

Trả lời

40

addBatchexecuteBatch cung cấp cho bạn cơ chế thực hiện chèn hàng loạt, nhưng bạn vẫn cần phải tự mình thực hiện thuật toán ghép.

Nếu bạn chỉ cần chồng mọi câu lệnh vào cùng một đợt, như bạn đang làm, thì bạn sẽ hết bộ nhớ. Bạn cần phải thực hiện/xóa lô mỗi n bản ghi. Giá trị của n tùy thuộc vào bạn, JDBC không thể đưa ra quyết định đó cho bạn. Kích thước lô lớn hơn, những thứ nhanh hơn sẽ đi, nhưng quá lớn và bạn sẽ bị mất trí nhớ và mọi thứ sẽ chậm lại hoặc thất bại. Nó phụ thuộc vào bộ nhớ của bạn.

Bắt đầu với kích thước hàng loạt là 1000 chẳng hạn và thử nghiệm với các giá trị khác nhau từ đó.

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

Nó là ra khỏi bộ nhớ bởi vì nó giữ tất cả các giao dịch trong bộ nhớ và chỉ gửi nó qua cơ sở dữ liệu khi bạn gọi executeBatch.

Nếu bạn không cần nó để được nguyên tử và sẽ thích có được hiệu suất tốt hơn, bạn có thể giữ một quầy và gọi executeBatch mỗi số n của hồ sơ.

+0

và giá trị n là gì? – craftsman

+3

Giá trị tùy thuộc vào bạn, bạn phải đánh giá ứng dụng của mình để có được giá trị tốt nhất mà bạn muốn cho việc giao dịch giữa bộ nhớ và hiệu suất. –

Các vấn đề liên quan