2010-03-07 17 views
7

Tôi đang sử dụng chế độ ngủ đông để cập nhật 20K sản phẩm trong cơ sở dữ liệu của tôi.sử dụng Hibernate với các sản phẩm tải 20K, sửa đổi các thực thể và cập nhật để db

Tính đến bây giờ tôi đang kéo đến các sản phẩm 20K, looping qua chúng và sửa đổi một số đặc tính và sau đó cập nhật cơ sở dữ liệu.

vậy:

load products 

foreach products 
    session begintransaction 
    productDao.MakePersistant(p); 
    session commit(); 

Tính đến bây giờ mọi thứ đều khá chậm so với jdbc tiêu chuẩn của bạn, những gì tôi có thể làm để tăng tốc?

Tôi chắc chắn tôi đang làm điều gì đó sai ở đây.

+0

Bạn có thực sự muốn nói * N * Hibernate (trong tiêu đề) không? – M4N

+0

Không dành cho Java - NHibernate dành cho .NET. – duffymo

+0

cố định nhờ tiêu đề. – Blankman

Trả lời

9

Các đúng nơi để nhìn vào trong tài liệu cho loại điều trị này là toàn bộ Chapter 13. Batch processing.

Ở đây, có một số sai lầm rõ ràng trong cách tiếp cận hiện tại của bạn:

  • bạn không nên bắt đầu/cam kết giao dịch cho mỗi lần cập nhật.
  • bạn nên cho phép JDBC trạm trộn và đặt nó vào một số lượng hợp lý (10-50):

    hibernate.jdbc.batch_size 20 
    
  • bạn nên flush() và sau đó clear() phiên đều đặn (mỗi n hồ sơ trong đó n là bằng tham số hibernate.jdbc.batch_size) hoặc nó sẽ tiếp tục phát triển và có thể phát nổ (với OutOfMemoryException) tại một số điểm.

Dưới đây, ví dụ đưa ra trong phần 13.2. Batch updates minh họa này:

Session session = sessionFactory.openSession(); 
Transaction tx = session.beginTransaction(); 

ScrollableResults customers = session.getNamedQuery("GetCustomers") 
    .setCacheMode(CacheMode.IGNORE) 
    .scroll(ScrollMode.FORWARD_ONLY); 
int count=0; 
while (customers.next()) { 
    Customer customer = (Customer) customers.get(0); 
    customer.updateStuff(...); 
    if (++count % 20 == 0) { 
     //flush a batch of updates and release memory: 
     session.flush(); 
     session.clear(); 
    } 
} 

tx.commit(); 
session.close(); 

Bạn cũng có thể xem xét sử dụng StatelessSession.

Một tùy chọn khác sẽ là sử dụng DML-style operations (trong HQL!): UPDATE FROM? EntityName (WHERE where_conditions)?.Đây ví dụ CẬP NHẬT HQL:

Session session = sessionFactory.openSession(); 
Transaction tx = session.beginTransaction(); 

String hqlUpdate = "update Customer c set c.name = :newName where c.name = :oldName"; 
// or String hqlUpdate = "update Customer set name = :newName where name = :oldName"; 
int updatedEntities = s.createQuery(hqlUpdate) 
     .setString("newName", newName) 
     .setString("oldName", oldName) 
     .executeUpdate(); 
tx.commit(); 
session.close(); 

Một lần nữa, hãy tham khảo tài liệu hướng dẫn cho các chi tiết (đặc biệt là làm thế nào để đối phó với các version hay timestamp giá trị tài sản bằng cách sử dụng từ khóa VERSIONED).

5

Nếu đây là pseudo-code, tôi khuyên bạn nên di chuyển các giao dịch bên ngoài vòng lặp, hoặc ít nhất là có một vòng lặp đôi nếu có tất cả các sản phẩm 20K trong một giao dịch duy nhất là quá nhiều:

load products 
foreach (batch) 
{ 
    try 
    { 
     session beginTransaction() 
     foreach (product in batch) 
     { 
      product.saveOrUpdate() 
     } 
     session commit() 
    } 
    catch (Exception e) 
    { 
     e.printStackTrace() 
     session.rollback() 
    } 
} 

Cũng , Tôi khuyên bạn nên tạo hàng loạt các UPDATE của bạn thay vì gửi từng cá nhân vào cơ sở dữ liệu. Có quá nhiều lưu lượng truy cập mạng theo cách đó. Ghép từng đoạn vào một mẻ và gửi tất cả cùng một lúc.

0

Cách nhanh nhất có thể để làm một cập nhật hàng loạt sẽ được chuyển đổi nó vào một câu lệnh SQL đơn và thực hiện nó như sql liệu trên phiên. Một cái gì đó như

update TABLE set (x=y) where w=z; 

Không mà bạn có thể cố gắng làm cho các giao dịch ít hơn và làm cập nhật theo lô:

start session 
start transaction 

products = session.getNamedQuery("GetProducs") 
    .setCacheMode(CacheMode.IGNORE) 
    .scroll(ScrollMode.FORWARD_ONLY); 
count=0; 
foreach product 
    update product 
    if (++count % 20 == 0) { 
     session.flush(); 
     session.clear(); 
    } 
} 

commit transaction 
close session 

Để biết thêm thông tin nhìn vào Hibernate Community Docs

1

Tôi đồng ý với câu trả lời ở trên về việc xem chương về xử lý theo lô.

Tôi cũng muốn thêm rằng bạn nên đảm bảo rằng bạn chỉ tải những gì cần thiết cho những thay đổi bạn cần thực hiện cho sản phẩm. Ý tôi là, nếu sản phẩm háo hức tải một số lượng lớn các đối tượng khác không quan trọng cho giao dịch này, bạn nên xem xét không tải các đối tượng được nối - nó sẽ tăng tốc độ tải sản phẩm và tùy thuộc vào độ bền của chúng. chiến lược, cũng có thể giúp bạn tiết kiệm thời gian khi làm cho sản phẩm liên tục trở lại.

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