只要没有超过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