2012-12-06 37 views
5

GORM hoạt động tốt trong hộp miễn là không có lô với hơn 10.000 đối tượng. Nếu không có tối ưu hóa, bạn sẽ phải đối mặt với các vấn đề outOfMemory.Grails hibernate session theo lô

Giải pháp phổ biến là tuôn() và clear() phiên mỗi n (EGN = 500) đối tượng:

Session session = sessionFactory.currentSession 
Transaction tx = session.beginTransaction(); 
def propertyInstanceMap = org.codehaus.groovy.grails.plugins.DomainClassGrailsPlugin.PROPERTY_INSTANCE_MAP 

Date yesterday = new Date() - 1 

Criteria c = session.createCriteria(Foo.class) 
c.add(Restrictions.lt('lastUpdated',yesterday)) 
ScrollableResults rawObjects = c.scroll(ScrollMode.FORWARD_ONLY) 

int count=0; 
while (rawObjects.next()) { 
    def rawOject = rawObjects.get(0); 

    fooService.doSomething() 

    int batchSize = 500 
    if (++count % batchSize == 0) { 
     //flush a batch of updates and release memory: 
     try{ 
      session.flush(); 
     }catch(Exception e){ 
      log.error(session) 
      log.error(" error: " + e.message) 
      throw e 
     } 
     session.clear(); 
     propertyInstanceMap.get().clear() 
    } 
} 

session.flush() 
session.clear() 
tx.commit() 

Nhưng có một số vấn đề tôi không thể giải quyết:

  1. Nếu tôi sử dụng currentSession, sau đó bộ điều khiển thất bại vì phiên trống rỗng
  2. Nếu tôi sử dụng sessionFactory.openSession(), thì currentSession vẫn được sử dụng bên trong FooService. Nguyên nhân tôi có thể sử dụng ký hiệu session.save (đối tượng). Nhưng điều này có nghĩa, rằng tôi phải sửa đổi fooService.doSomething() và mã trùng lặp cho hoạt động đơn lẻ (ký hiệu grails chung như fooObject.save()) và thao tác lô (session.save (fooObject()) .. ký hiệu).
  3. Nếu tôi sử dụng Foo.withSession {session->} hoặc Foo.withNewSession {session->}, thì đối tượng của lớp Foo sẽ bị xóa bởi session.clear() như mong đợi. Tất cả các đối tượng khác không bị xóa(), điều gì dẫn đến rò rỉ bộ nhớ.
  4. Nguyên nhân tôi có thể sử dụng lệnh đuổi (đối tượng) để làm thủ công xóa phiên. Nhưng gần như không thể có được tất cả các đối tượng liên quan, do tự động tìm kiếm các cuộc tấn công.

Vì vậy, tôi không biết cách giải quyết các vấn đề của mình mà không làm phức tạp hơn FooService.doSomething(). Tôi đang tìm một cái gì đó như withSession {} cho tất cả các tên miền. Hoặc để lưu phiên lúc bắt đầu (Session tmp = currentSession) và làm một cái gì đó như sessionFactory.setCurrentSession (tmp). Cả hai đều không tồn tại!

Bất kỳ ý tưởng nào cũng được chào đón!

+2

Điều này giống như công việc nên được thực hiện hoàn toàn trong một phương pháp dịch vụ. Nếu trong phương thức dịch vụ, bạn sử dụng 'currentSession', bộ điều khiển của bạn có hoạt động không? – doelleri

+3

Tôi đồng ý với @doelleri. Dịch vụ là nơi tuyệt vời để làm điều đó. Ngoài ra, hãy nhớ rằng theo mặc định chúng là giao dịch, nếu bạn muốn xử lý thủ công trạng thái, hãy sử dụng 'Domain.withTransaction' và đặt' static transactional = false' hoặc cho phép dịch vụ xử lý commit/rollback. –

+0

Mã tôi đã đăng ở đó đã nằm trong một phương thức dịch vụ. Có, tôi có thể sử dụng ngữ cảnh giao dịch của phương thức dịch vụ, nhưng nó sẽ không giải quyết được vấn đề của tôi. @doelleri - Câu trả lời cho câu hỏi của bạn là: bộ điều khiển phanh, để người dùng không thể làm gì thêm trong ứng dụng ngoại trừ đóng trình duyệt.(xem vấn đề 1) – Waldemar

Trả lời

0

Một cách tiếp cận để sửa đổi những gì bạn đang làm sẽ là:

  1. Vòng qua toàn bộ bộ sưu tập của bạn (rawObjects) và lưu một danh sách tất cả các id cho các đối tượng.
  2. Lặp qua danh sách các id. Tại mỗi lần lặp lại, chỉ tìm kiếm một đối tượng duy nhất, theo id của nó.

Sau đó, sử dụng cùng một lần xóa định kỳ của bộ nhớ cache phiên như bạn hiện đang làm.

Nhân tiện, someone else has suggested an approach similar to yours. Nhưng lưu ý rằng mã trong liên kết này không chính xác; các dòng xóa phiên nên nằm trong câu lệnh if, giống như bạn có trong giải pháp của mình.

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