只要沒有超過10,000個對象的批處理,GORM就可以正常工作。沒有優化,你將面臨outOfMemory問題。批量Grails休眠會話
的常見解決方案是沖洗()和清除()會話每個n(EGN = 500)對象:
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()
但也存在一些問題,我不能解決:
- 如果我使用currentSession,那麼控制器由於會話爲空而失敗
- 如果我使用sessionFactory.openSession(),那麼currentSession仍然在FooService中使用。因爲我可以使用session.save(object)符號。但是這意味着我必須修改fooService.doSomething()併爲單個操作(fooObject.save())和批處理操作(session.save(fooObject())..表示法)複製代碼。
- 如果我使用Foo.withSession {session->}或Foo.withNewSession {session->},那麼Foo Class的對象按預期由session.clear()清除。所有其他對象不清除(),導致內存泄漏。
- 因爲我可以使用evict(object)來手動清除會話。但由於自動修飾聯繫,幾乎不可能得到所有相關的對象。
所以我不知道如何解決我的問題,而不是使FooService.doSomething()更復雜。我正在爲所有域尋找類似withSession {}的內容。或者在開始時保存會話(Session tmp = currentSession)並執行諸如sessionFactory.setCurrentSession(tmp)之類的操作。兩者都不存在!
任何想法都是好的!
這看起來像應完全在服務方法中完成的工作。如果在服務方法中使用'currentSession',你的控制器是否仍然工作? – doelleri
我同意@doelleri。服務是做這件事的好地方。此外,請記住,默認情況下它們是事務性的,如果您想手動處理狀態,請使用'Domain.withTransaction'並設置'static transactional = false'或讓服務處理提交/回滾。 –
我在那裏發佈的代碼已經在服務方法中。是的,我可以使用服務方法的事務上下文,但它不能解決我的問題。 @doelleri - 你的問題的答案是:控制器剎車,這樣除了關閉瀏覽器之外,用戶不能在應用程序中做更多的事情。(見問題1) – Waldemar