2012-05-14 43 views
23

Có cách nào để chúng tôi có thể sử dụng chèn hàng loạt bằng JPA EntityManager hay không. Tôi biết không có cách trực tiếp để đạt được điều này nhưng phải có một số cách để đạt được cơ chế này.Chèn hàng loạt bằng cách sử dụng JPA EntityManager

Thực tế, đối với mọi thao tác chèn, nó lấy tôi 300ms mà tôi muốn giảm bằng cách sử dụng chèn hàng loạt thay vì chèn đơn.

Đây là mã tôi đang sử dụng hiện đang thực hiện cho chèn đơn

 @PersistenceContext(unitName = "testing") 
     EntityManager eM; 

     Query querys = this.eM.createNativeQuery(insertQuery); 
     for (String s : someList) { 
      //setting parameters 
      querys.executeUpdate(); 
     } 

Cảm ơn trước.

Trả lời

11

có thể thực hiện ghi hàng loạt bằng cách sử dụng JPA, nhưng nó phụ thuộc rất nhiều vào việc triển khai cụ thể nhà cung cấp, cơ sở dữ liệu và trình điều khiển JDBC của bạn. Ví dụ: article giải thích cách bật viết hàng loạt (tối ưu hóa # 8) bằng EclipseLink JPA 2.3 và cơ sở dữ liệu Oracle. Tìm các tham số cấu hình tương tự trong môi trường cụ thể của bạn.

+0

Hi, u có thể cung cấp cho tôi một số đoạn mã làm thế nào để sử dụng cùng mã được cung cấp ở trên. – Ran

+0

@Rana như tôi đã nói ở trên: nó phụ thuộc vào nhà cung cấp kiên trì bạn đang sử dụng - và tôi không thể nói bằng cách nhìn vào mã, bạn phải nói với tôi. –

+1

Xin chào, tôi đang sử dụng org.eclipse.persistence.jpa.PersistenceProvider. Ngoài ra xin vui lòng cho tôi biết nếu có bất kỳ hạn chế bằng cách sử dụng chèn hàng loạt. – Ran

3

Bản thân JPA không có bất kỳ cài đặt nào cho việc tạo nhóm. Tuy nhiên có một số cài đặt phụ thuộc vào việc triển khai thực hiện. Here is an example for hibernate.

21

Tùy thuộc vào việc giao dịch có bao quanh vòng lặp hay không, việc tạo nhóm thường xảy ra trong trường hợp của bạn.

JPA sẽ thu thập tất cả các bản cập nhật của bạn trong bộ nhớ cache L1 và thường ghi tất cả cho DB trong một lô khi giao dịch cam kết. Điều này không thực sự khác với việc tạo khối trong JDBC, trong đó mỗi lô-hàng bạn thêm cũng tạm thời trong bộ nhớ cho đến khi bạn gọi một phương thức cập nhật. Có thể có vấn đề là bạn không có đảm bảo rằng JPA thực sự thực hiện việc này theo lô và nếu thực hiện điều này tại giao dịch hoặc khi đạt đến ngưỡng, nhưng tôi thấy rằng trong thực tế trong hầu hết các trường hợp và đặc biệt là các trường hợp liên quan đến vòng lặp cập nhật đơn giản như vậy, nó thực sự thực hiện theo đợt.

Một vấn đề ở đây là ngay cả khi JPA thực sự đã thực hiện theo đợt, bạn vẫn có thể muốn kiểm soát kích cỡ lô. Các bài báo được liên kết bởi các câu trả lời khác cung cấp thông tin khá hữu ích cho điều đó.

Cuối cùng, bạn nên lưu ý rằng bộ nhớ cache L1 của bạn tiếp tục phát triển trong một vòng lặp, vì vậy nếu số lượng cập nhật thực sự lớn, hãy xóa định kỳ nó. Ngoài ra, nếu logic kinh doanh của bạn có thể duy trì nó, hãy cập nhật từng phần trong nhiều giao dịch. Ví dụ. mục 0 đến 100.000 trong giao dịch 1, 100.001 đến 200.000 trong giao dịch 2, v.v.

+0

Bây giờ tôi đã sử dụng jpa dữ liệu mùa xuân, vì vậy bạn có nghĩa là nếu tôi cập nhật đối tượng trong một vòng lặp bên trong một phương thức và phương thức này được đánh dấu bằng @Transactional, nó sẽ tự động cập nhật hàng loạt như cập nhật hàng loạt jdbc. – zhuguowei

12

Tôi biết đây là câu hỏi khá cũ với câu trả lời được chấp nhận. Tuy nhiên, tôi muốn đưa ra một câu trả lời mới cho chủ đề rất cụ thể này "chèn hàng loạt JPA".

@PersistenceContext 
private EntityManager entityManager; 

@Value("${hibernate.jdbc.batch_size}") 
private int batchSize; 

public <T extends MyClass> Collection<T> bulkSave(Collection<T> entities) { 
    final List<T> savedEntities = new ArrayList<T>(entities.size()); 
    int i = 0; 
    for (T t : entities) { 
    savedEntities.add(persistOrMerge(t)); 
    i++; 
    if (i % batchSize == 0) { 
     // Flush a batch of inserts and release memory. 
     entityManager.flush(); 
     entityManager.clear(); 
    } 
    } 
    return savedEntities; 
} 

private <T extends MyClass> T persistOrMerge(T t) { 
    if (t.getId() == null) { 
    entityManager.persist(t); 
    return t; 
    } else { 
    return entityManager.merge(t); 
    } 
} 

Nguồn: http://frightanic.com/software-development/jpa-batch-inserts/

+2

Tôi đoán chúng ta cần phải một lần nữa 'flush()' và 'clear()' ở cuối để lưu bất kỳ đối tượng còn lại nào không hoàn thành kích thước lô của chúng ta? –

+0

Nghe đúng, cảm ơn @RamPatra. –

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