只要没有超过 10.000 个对象的批次,GORM 开箱即用就可以正常工作。如果不进行优化,您将面临 outOfMemory 问题。
常见的解决方案是对每个 n (egn=500) 个对象刷新() 和 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(),那么 currentSession 仍然在 FooService 中使用。当然,我可以使用 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) 的操作。两者都不存在!
任何想法都是受欢迎的!