Performance 成批执行Grails hibernate会话

Performance 成批执行Grails hibernate会话,performance,hibernate,grails,gorm,Performance,Hibernate,Grails,Gorm,只要批处理对象不超过10000个,GORM就可以在开箱即用的情况下正常工作。如果没有优化,您将面临outOfMemory问题 常见的解决方案是对每个n(例如n=500)对象刷新()和清除()会话: 但有些问题我无法解决: 如果我使用currentSession,则控制器会失败,因为会话为空 如果我使用sessionFactory.openSession(),那么当前会话仍然在FooService中使用。当然,我可以使用session.save(object)符号。但这意味着,我必须修改fooSe

只要批处理对象不超过10000个,GORM就可以在开箱即用的情况下正常工作。如果没有优化,您将面临outOfMemory问题

常见的解决方案是对每个n(例如n=500)对象刷新()和清除()会话:

但有些问题我无法解决:

  • 如果我使用currentSession,则控制器会失败,因为会话为空
  • 如果我使用sessionFactory.openSession(),那么当前会话仍然在FooService中使用。当然,我可以使用session.save(object)符号。但这意味着,我必须修改fooService.doSomething()和单个操作(常见的grails表示法,如foooObject.save())和批处理操作(session.save(foooObject())…表示法)的重复代码
  • 如果我使用Foo.withSession{session->}或Foo.withNewSession{session->},那么Foo类的对象将按预期由session.clear()清除。未清除所有其他对象(),这将导致内存泄漏
  • 当然,我可以使用逐出(object)手动清除会话。但由于自动获取关联,几乎不可能获取所有相关对象
  • 因此,我不知道如何在不使FooService.doSomething()更复杂的情况下解决我的问题。我正在为所有域寻找类似于with session{}的东西。或者在开始时保存会话(会话tmp=currentSession),并执行类似sessionFactory.setCurrentSession(tmp)的操作。两者都不存在


    任何想法都是好的

    我建议对这种批处理使用无状态会话。请参阅本文:

    修改后的方法是:

  • 循环遍历整个集合(
    rawObjects
    ),并保存这些对象的所有ID的列表
  • 在ID列表上循环。在每次迭代中,只查找单个对象的id
  • 然后像现在一样定期清除会话缓存


    顺便说一下。但请注意,此链接中的代码不正确;清除会话的行应该在if语句中,就像您在解决方案中所做的一样。

    这看起来像是应该完全在服务方法中完成的工作。如果在维修方法中,您使用了
    currentSession
    ,您的控制器是否仍然工作?我同意@doelleri的说法。服务业是实现这一目标的最佳场所。另外,请记住,默认情况下它们是事务性的,如果您想手动处理状态,请使用
    Domain.withTransaction
    并设置
    static transactional=false
    ,或者让服务负责提交/回滚。我在那里发布的代码已经在服务方法中。是的,我可以使用服务方法的事务上下文,但它不能解决我的问题@doelleri-对你的问题的答案是:控制器会刹车,因此用户除了关闭浏览器外,在应用程序中不能做其他事情。(参见问题1)查看。很容易集成到grails中,非常强大,谢谢您的建议!我想避免使用Spring批处理,因为它很复杂。我已经集成了quarz作业,这意味着springbatch和quarz在一个应用程序中将有两种作业调度方法。有没有更简单的解决办法?
    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()