Grails hibernate会话分批

Wal*_*mar 5 performance grails hibernate grails-orm

只要没有超过10,000个对象的批处理,GORM就可以正常工作.如果没有优化,您将面临outOfMemory问题.

常见的解决方案是每次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()
Run Code Online (Sandbox Code Playgroud)

但是有些问题我无法解决:

  1. 如果我使用currentSession,则控制器因会话为空而失败
  2. 如果我使用sessionFactory.openSession(),那么currentSession仍然在FooService中使用.因为我可以使用session.save(object)表示法.但这意味着,我必须修改fooService.doSomething()并复制单个操作的代码(常见的grails表示法,如fooObject.save())和批处理操作(session.save(fooObject())..表示法).
  3. 如果我使用Foo.withSession {session->}或Foo.withNewSession {session->},那么Foo类的对象将被session.clear()按预期清除.所有其他对象都未清除(),导致内存泄漏的原因.
  4. 因为我可以使用evict(对象)来手动清除会话.但是,由于自动提取关联,几乎不可能获得所有相关对象.

所以我不知道如何在不使FooService.doSomething()更复杂的情况下解决我的问题.我正在为所有域寻找类似withSession {}的东西.或者在开始时保存会话(Session tmp = currentSession)并执行类似sessionFactory.setCurrentSession(tmp)的操作.两者都不存在!

任何想法都很好!

ste*_*nix 1

我建议使用无状态会话进行这种批处理。请参阅这篇文章:使用 StatelessSession 进行批处理