【发布时间】:2017-02-22 15:21:57
【问题描述】:
只要没有超过 10.000 个对象的批次,GORM 开箱即用就可以正常工作。如果不进行优化,您将面临 outOfMemory 问题。
常见的解决方案是对会话中的每个 n(例如 n=500)个对象进行 flush() 和 clear():
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(),那么在 FooService 内部仍然使用 currentSession。当然,我可以使用 session.save(object) 表示法。但这意味着,我必须修改 fooService.doSomething() 并为单个操作(常见的 grails 表示法,如 fooObject.save() )和批处理操作(session.save(fooObject() ).. 表示法)修改代码。李>
- 如果我使用 Foo.withSession{session->} 或 Foo.withNewSession{session->},那么 Foo 类的对象会按预期由 session.clear() 清除。所有其他对象都没有清除(),导致内存泄漏。
- 当然,我可以使用 evict(object) 手动清除会话。但由于关联的自动获取,几乎不可能获取所有相关对象。
所以我不知道如何在不使 FooService.doSomething() 更复杂的情况下解决我的问题。我正在为所有域寻找类似 withSession{} 的东西。或者在开始时保存会话(Session tmp = currentSession)并执行类似 sessionFactory.setCurrentSession(tmp) 的操作。两者都不存在!
欢迎任何想法!
【问题讨论】:
-
这看起来像是应该完全在服务方法中完成的工作。如果在服务方法中,你使用
currentSession,你的控制器还能工作吗? -
我同意@doelleri。服务是做这件事的好地方。另外,请记住,默认情况下它们是事务性的,如果您想手动处理状态,请使用
Domain.withTransaction并设置static transactional = false或让服务负责提交/回滚。 -
我发布的代码已经在服务方法中。是的,我可以使用服务方法的事务上下文,但它不能解决我的问题。 @doelleri - 你的问题的答案是:控制器刹车,所以用户除了关闭浏览器之外不能在应用程序中做任何其他事情。 (见问题 1)
-
看看Spring Batch。易于集成到 grails 中并且非常强大
-
感谢您的建议!由于 Spring Batch 的复杂性,我想避免使用它。我已经集成了 quarz 作业,这意味着使用 Spring Batch 和 Quarz 在一个应用程序中将有两种作业调度方法。有没有更简单的解决方案?
标签: performance hibernate grails grails-orm