2012-08-23 21 views
7

Dưới đây là mã mà tôi đang sử dụng để chèn multiple records(around 5000-7000) vào Cơ sở dữ liệu Oracle bằng cách sử dụng Tuyên bố được Chuẩn bị.Sử dụng Tuyên bố đã Chuẩn bị nhiều lần hiệu quả

Cách tôi hiện đang làm là tốt? Hoặc nó có thể được cải thiện hơn bằng cách sử dụng một số batch thing?

pstatement = db_connection.prepareStatement(PDSLnPConstants.UPSERT_SQL); 

for (Entry<Integer, LinkedHashMap<Integer, String>> entry : MAPPING.entrySet()) { 

    pstatement.setInt(1, entry.getKey()); 
    pstatement.setString(2, entry.getValue().get(LnPConstants.CGUID_ID)); 
    pstatement.setString(3, entry.getValue().get(LnPConstants.PGUID_ID)); 
    pstatement.setString(4, entry.getValue().get(LnPConstants.SGUID_ID)); 
    pstatement.setString(5, entry.getValue().get(LnPConstants.UID_ID)); 
    pstatement.setString(6, entry.getValue().get(LnPConstants.ULOC_ID)); 
    pstatement.setString(7, entry.getValue().get(LnPConstants.SLOC_ID)); 
    pstatement.setString(8, entry.getValue().get(LnPConstants.PLOC_ID)); 
    pstatement.setString(9, entry.getValue().get(LnPConstants.ALOC_ID)); 
    pstatement.setString(10, entry.getValue().get(LnPConstants.SITE_ID)); 
    pstatement.executeUpdate(); 

    pstatement.clearParameters(); 
} 

Udpated Mã Rằng tôi đang dùng: -

public void runNextCommand() { 

    Connection db_connection = null; 
    PreparedStatement pstatement = null; 
    int batchLimit = 1000; 
    boolean autoCommit = false; 

    try { 
     db_connection = getDBConnection(); 

     autoCommit = db_connection.getAutoCommit(); 
     db_connection.setAutoCommit(false); //Turn off autoCommit 
     pstatement = db_connection.prepareStatement(LnPConstants.UPSERT_SQL); // create a statement 

     for (Entry<Integer, LinkedHashMap<Integer, String>> entry : GUID_ID_MAPPING.entrySet()) { 
      pstatement.setInt(1, entry.getKey()); 
      pstatement.setString(2, entry.getValue().get(LnPConstants.CGUID_ID)); 
      pstatement.setString(3, entry.getValue().get(LnPConstants.PGUID_ID)); 
      pstatement.setString(4, entry.getValue().get(LnPConstants.SGUID_ID)); 
      pstatement.setString(5, entry.getValue().get(LnPConstants.UID_ID)); 
      pstatement.setString(6, entry.getValue().get(LnPConstants.ULOC_ID)); 
      pstatement.setString(7, entry.getValue().get(LnPConstants.SLOC_ID)); 
      pstatement.setString(8, entry.getValue().get(LnPConstants.PLOC_ID)); 
      pstatement.setString(9, entry.getValue().get(LnPConstants.ALOC_ID)); 
      pstatement.setString(10, entry.getValue().get(LnPConstants.SITE_ID)); 
      pstatement.addBatch(); 

      batchLimit--; 

      if(batchLimit == 0){ 
       pstatement.executeBatch(); 
       pstatement.clearBatch(); 
       batchLimit = 1000; 
      } 
      pstatement.clearParameters(); 
     } 

    } catch (SQLException e) { 
     getLogger().log(LogLevel.ERROR, e); 
    } finally { 
     try { 
      pstatement.executeBatch(); 
      db_connection.commit(); 
      db_connection.setAutoCommit(autoCommit); 
     } catch (SQLException e1) { 
      getLogger().log(LogLevel.ERROR, e1.getMessage(), e1.fillInStackTrace()); 
     } 

     if (pstatement != null) { 
      try { 
       pstatement.close(); 
       pstatement = null; 
      } catch (SQLException e) { 
       getLogger().log(LogLevel.ERROR, e.getMessage(), e.fillInStackTrace()); 
      } 
     } 
     if (db_connection!= null) { 
      try { 
       db_connection.close(); 
       db_connection = null; 
      } catch (SQLException e) { 
       getLogger().log(LogLevel.ERROR, e.getMessage(), e.fillInStackTrace()); 
      } 
     } 
    } 
} 
+0

(Đảm bảo các giao dịch đang được sử dụng đúng cách. Nếu không mã được đăng "sẽ không tốt", thậm chí là [sử dụng lại các câu lệnh đã được chuẩn bị sẵn. ") INSIT/UPDATE là" fast ". COMMIT là" chậm ".) –

Trả lời

8

Bạn có thể nghĩ rằng sử dụng addBatch() và thực hiện một mặt sau của báo cáo trong một shot. Ngoài ra, như @pst đã nhận xét trong câu hỏi của bạn, hãy xem xét sử dụng .

Cách bạn sẽ làm là như sau:

boolean autoCommit = connection.getAutoCommit(); 
try{ 
    connection.setAutoCommit(false //Turn off autoCommit 
    pstatement = db_connection.prepareStatement(PDSLnPConstants.UPSERT_SQL); 

    int batchLimit = 1000; 

    try{ 
     for (Entry<Integer, LinkedHashMap<Integer, String>> entry : MAPPING.entrySet()) { 
      pstatement.setInt(1, entry.getKey()); 
      pstatement.setString(2, entry.getValue().get(LnPConstants.CGUID_ID)); 
      pstatement.setString(3, entry.getValue().get(LnPConstants.PGUID_ID)); 
      pstatement.setString(4, entry.getValue().get(LnPConstants.SGUID_ID)); 
      pstatement.setString(5, entry.getValue().get(LnPConstants.UID_ID)); 
      pstatement.setString(6, entry.getValue().get(LnPConstants.ULOC_ID)); 
      pstatement.setString(7, entry.getValue().get(LnPConstants.SLOC_ID)); 
      pstatement.setString(8, entry.getValue().get(LnPConstants.PLOC_ID)); 
      pstatement.setString(9, entry.getValue().get(LnPConstants.ALOC_ID)); 
      pstatement.setString(10, entry.getValue().get(LnPConstants.SITE_ID)); 

      pstatement.addBatch(); 
      batchLimit--; 

      if(batchLimit == 0){ 
       pstatement.executeBatch(); 
       pstatement.clearBatch 
       batchLimit = 1000; 
      } 
      pstatement.clearParameters(); 
     } 
    }finally{ 
     //for the remaining ones 
     pstatement.executeBatch(); 

     //commit your updates 
     connection.commit(); 
    } 
}finally{ 
    connection.setAutoCommit(autoCommit); 
} 

Ý tưởng là để thiết lập một giới hạn để cập nhật hàng loạt và thực hiện một bản cập nhật cơ sở dữ liệu chỉ khi bạn đạt đến một giới hạn nhất định. Bằng cách này, bạn đang giới hạn một cuộc gọi cơ sở dữ liệu đến một lần batchLimit mà bạn đã xác định. Bằng cách này nó sẽ nhanh hơn.

Cũng lưu ý cho số transaction, tôi vừa hiển thị cách thức và thời điểm đến commit. Điều này có thể không phải lúc nào cũng là điểm chính xác để commit vì quyết định này sẽ dựa trên yêu cầu của bạn. Bạn cũng có thể muốn thực hiện rollback trong trường hợp ngoại lệ. Vì vậy, nó tùy thuộc vào bạn để quyết định.

Hãy xem hướng dẫn "Using Transaction" để có hình ảnh tốt hơn về cách sử dụng transaction.

+0

Bạn có thể cung cấp cho tôi một ví dụ về mã của tôi để tôi có được hình ảnh rõ ràng về cách sử dụng 'addBatch()' ở đây không? Nó sẽ giúp ích rất nhiều. – AKIWEB

+0

@ Nevzz03: Đã cập nhật câu trả lời của tôi với mã mẫu. Hy vọng điều này sẽ giúp :) – Sujay

+0

Cảm ơn Sujay vì câu trả lời chi tiết.Đánh giá cao sự giúp đỡ của bạn. Tôi vừa cập nhật câu hỏi của mình bằng mã đầy đủ mà tôi đang sử dụng hiện tại theo đề xuất của bạn sau khi thực hiện thay đổi. Bạn có thể xem và cho tôi biết nếu mọi thứ có vẻ tốt với bạn và tôi không làm gì sai? – AKIWEB

1

Đoạn mã của bạn có vẻ tốt với tôi.

Chỉ để làm sạch mã, tôi sẽ đặt entry.getValue() thành biến số (gọi là value).
Và không cần phải gọi clearParameters().

Cuối cùng, hãy nhớ vứt bỏ chính xác câu lệnh đã chuẩn bị khi bạn không cần nó nữa (close()).

+0

Cảm ơn gd1 vì các đề xuất. Tại sao bạn nghĩ rằng không cần phải gọi 'clearParameters()'? Tôi chỉ muốn biết từ quan điểm kiến ​​thức. – AKIWEB

+1

Khi bạn đặt tham số, giá trị trước đó sẽ bị xóa. :) – gd1

1

Có, thực hiện cập nhật hàng loạt sẽ cải thiện đáng kể hiệu suất của bạn. Chỉ cần google cho nó, câu trả lời ưa thích của tôi là this one from Mkyong.com. Khác, mã của bạn trông ok. "clearParameters()" là không thực sự cần thiết, nó thậm chí có thể tiêu thụ một số chu kỳ xử lý. Quan trọng: nếu AutoCommit được kích hoạt, đừng quên vô hiệu hóa nó trước, và kích hoạt nó sau khi thực hiện cập nhật, điều này mang lại một sự cải tiến to lớn.

PS

Đề xuất trên cũng dựa trên kinh nghiệm của tôi. Tôi vừa lưu ý rằng câu hỏi này đã được hỏi here at Stackoverflow và câu trả lời rất chi tiết. Thông tin thêm về PreparedStatements và lô có thể được tìm thấy trong tài liệu Oracle here và về Giao dịch (AutoCommit) here.

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