2010-06-18 26 views
5

Các chức năng mã bên dưới, nhưng Hibernate không bao giờ cho phép việc nắm giữ bất kỳ đối tượng nào. Gọi số session.clear() sẽ gây ra các ngoại lệ liên quan đến việc tìm nạp một lớp đã tham gia, và gọi session.evict(currentObject) trước khi truy xuất đối tượng tiếp theo cũng không giải phóng được bộ nhớ. Cuối cùng tôi xả không gian của tôi.Hibernate: Đi bộ hàng triệu hàng và không bị rò rỉ bộ nhớ

Kiểm tra vùng heap của tôi, StatefulPersistenceContext là gốc của trình thu thập rác cho tất cả các tham chiếu trỏ đến đối tượng của tôi.

public class CriteriaReportSource implements JRDataSource { 

    private ScrollableResults sr; 
    private Object currentObject; 
    private Criteria c; 
    private static final int scrollSize = 10; 
    private int offset = 1; 

    public CriteriaReportSource(Criteria c) { 
     this.c = c; 
     advanceScroll(); 
    } 

    private void advanceScroll() { 
//  ((Session) Main.em.getDelegate()).clear(); 
     this.sr = c.setFirstResult(offset) 
        .setMaxResults(scrollSize) 
        .scroll(ScrollMode.FORWARD_ONLY); 
     offset += scrollSize; 
    } 

    public boolean next() { 
     if (sr.next()) { 
      currentObject = sr.get(0); 
      if (sr.isLast()) { 
       advanceScroll(); 
      } 
      return true; 
     } 

     return false; 
    } 

    public Object getFieldValue(JRField jrf) throws JRException { 
     Object retVal = null; 
     if(currentObject == null) { return null; } 
     try { 
      retVal = PropertyUtils.getProperty(currentObject, jrf.getName()); 
     } catch (Exception ex) { 
      Logger.getLogger(CriteriaReportSource.class.getName()).log(Level.SEVERE, null, ex); 
     } 
     return retVal; 
    } 
} 
+0

Tôi đã xem các ví dụ về điều này trong [Tham chiếu Hibernate] (http://docs.jboss.org/hibernate/core/3.3/reference/en/html/batch.html#batch-update), tuy nhiên, ở đó 'session.flush()' được gọi trước 'session.clear()'. Bạn có thể thử liệu nó có tạo nên sự khác biệt không? –

+0

Cơ sở dữ liệu là gì? Không phải tất cả đều hỗ trợ di chuyển con trỏ đúng. Ngoài ra, tôi không thấy bạn đóng ScrollableResults. –

+0

Tôi đã sử dụng MySQL. –

Trả lời

1

Tôi nghĩ rằng một trong những vấn đề của tôi là

if (sr.isLast()) { 
    advanceScroll(); 
    //... 

kết hợp với

((Session) Main.em.getDelegate()).clear(); 
//Also, "Main.em.clear()" should do... 

dẫn đến đỏ bừng d atabase ra một chạy quá sớm. Đó là nguyên nhân của các ngoại lệ liên quan đến các bộ sưu tập. Bộ sưu tập không thể được xử lý trong một StatelessSession, do đó, đó là ra khỏi bảng. Tôi không biết tại sao session.evict(currentObject) không hoạt động khi Session.clear() hoạt động, nhưng đó là cách tôi sẽ phải xử lý ngay bây giờ. Tôi sẽ ném các điểm câu trả lời cho bất cứ ai có thể hình dung ra câu trả lời đó.

Vì vậy, hiện tại, chúng tôi có câu trả lời. Một cửa sổ cuộn thủ công là bắt buộc, việc đóng ScrollableResults không có ích, và tôi cần chạy đúng Session.clear().

+0

Điều này sẽ được sửa trong câu hỏi chứ không phải là câu trả lời. –

+1

Tại sao vậy? Điều này giải quyết thành công vấn đề của tôi. Trong khi nó đặt ra một câu hỏi về Session.evict, mà tôi có thể di chuyển qua, đó là câu trả lời. –

0

Vài điều tôi sẽ đề nghị:

Thử gọi setCacheMode(CacheMode.IGNORE) trên Tiêu chuẩn trước khi mở nó.

Trong phương thức advanceScroll(), thêm if (sr != null) sr.close(); để các ScrollableResults trước đó bị đóng trước khi bạn chuyển nhượng lại cho phiên bản mới.

Một câu hỏi: Lý do để gọi setMaxSize(), và sau đó theo dõi bù trừ và sau đó mở lại kết quả có thể cuộn, tại sao không chỉ thực hiện việc này?

public CriteriaReportSource(Criteria c) { 
    this.c = c; 
    this.sr = c.setCacheMode(CacheMode.IGNORE) 
       .scroll(ScrollMode.FORWARD_ONLY); 
} 


public boolean next() { 
    if (sr.next()) { 
     currentObject = sr.get(0); 
     return true; 
    } 
    return false; 
} 
+0

Thật không may, không có đề xuất nào trong câu trả lời này được thực hiện. setMaxSize() và như vậy đã cố gắng giải quyết vấn đề bằng cách kiểm soát cửa sổ của những gì được truy vấn. Có hoặc không có chúng, bộ nhớ tiếp tục phát triển. Nr.close() cũng không thành công. –

+0

Rất tiếc khi nghe điều đó. Cung cấp cho StatelessSession rằng Pascal đã đề cập, đó có thể là đặt cược tốt nhất của bạn. –

3

Đừng sử dụng phiên stateful đây, nó chỉ là KHÔNG đúng công cụ để đi hàng triệu hàng và xây dựng một báo cáo. Sử dụng The StatelessSession interface để thay thế.

Nếu sử dụng MySQL Connector/J thậm chí đó là chưa đủ, bạn cũng cần phải đánh bại các đệm nội bộ thực hiện bởi các trình điều khiển JDBC, với this:

Query query = session.createQuery(query); 
query.setReadOnly(true); 
// MIN_VALUE gives hint to JDBC driver to stream results 
query.setFetchSize(Integer.MIN_VALUE); 
ScrollableResults results = query.scroll(ScrollMode.FORWARD_ONLY); 
// iterate over results 
while (results.next()) { 
    Object row = results.get(); 
    // process row then release reference 
    // you may need to evict() as well 
} 
results.close(); 
+1

Hiện tại, sử dụng StatelessSession giải quyết vấn đề bộ nhớ, nhưng tăng tất cả các địa ngục khi kết nối OneToMany liên quan được truy cập (tải chậm). Một loại thắng lợi thú vị. Bất kỳ đề xuất nào trong khi tôi đi thử nghiệm nếu tải mong muốn giải quyết vấn đề này? –

+0

Tắt StatelessSession không thể xử lý các bộ sưu tập. Tôi đã tìm cách sử dụng Stateful và kiểm soát trí nhớ của mình. Xem câu trả lời của tôi cho câu hỏi của riêng tôi. –