常见的解决方案是每次n(例如n = 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()
但是有些问题我无法解决:
所以我不知道如何在不使FooService.doSomething()更复杂的情况下解决我的问题。我正在为所有域寻找类似withSession {}的东西。或者在开始时保存会话(Session tmp = currentSession)并执行类似sessionFactory.setCurrentSession(tmp)的操作。两者都不存在!
任何想法都很好!
答案 0 :(得分:1)
我建议使用无状态会话进行这种批处理。请参阅此帖子:Using StatelessSession for Batch processing
答案 1 :(得分:0)
您正在做的改进方法是:
rawObjects
)并保存这些对象的所有ID列表。然后像现在一样使用相同的会话缓存定期清除。
顺便说一句,someone else has suggested an approach similar to yours。但请注意,此链接中的代码不正确;清除会话的行应该在if语句中,就像你在解决方案中一样。