代码之家  ›  专栏  ›  技术社区  ›  Rob Hruska MegalomanINA

GrailsQuartz作业在升级后没有休眠会话,导致lazyinitializationException

  •  1
  • Rob Hruska MegalomanINA  · 技术社区  · 15 年前

    我已经将Grails1.0.4应用程序升级到了1.1.1。升级后,在执行Quartz作业时(使用Quartz插件0.4.1),我会反复获得异常。该插件用于通过服务使用简单触发器和cron触发器手动计划作业(下面的解释代码):

    class SchedulerService implements InitializingBean
    {
        static scope = 'singleton'
        ...
        def schedule(def batch) {
            JobDetail job = new JobDetail(uniqueId, groupName, BatchJob.class, false, false, true)
            job.jobDataMap.put("batchId", batch.id)
    
            SimpleTrigger trigger = new SimpleTrigger(triggerId, triggerGroup, 0)
    
            SchedulerFactory factory = new SchedulerFactory()
            factory.initialize(properties)
            Scheduler scheduler = factory.getScheduler()
    
            scheduler.scheduleJob(job, trigger)
        }
        ...
    }
    

    我的批处理作业设置如下:

    class BatchJob implements Job, InterruptableJob
    {
        static triggers = {}
        void execute(JobExecutionContext context) {
            def batch = Batch.get(context.jobDetail.jobDataMap.getLongValue("batchId"))
            // the next line is "line 49" from the stack trace below
            def foo = batch.batchStatus.description
        }
    }
    

    以下是batch.groovy(域)的缩写定义:

    class Batch
    {
        BatchStatus batchStatus // relationship
    }
    

    然而,何时 schedulerService.schedule() 使用现有的已保存批调用时,我收到以下异常:

    org.hibernate.LazyInitializationException: could not initialize proxy - no Session
            at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:86)
            at org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsHibernateUtil.unwrapProxy(GrailsHibernateUtil.java:311)
            at org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsHibernateUtil$unwrapProxy.call(Unknown Source)
            at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:40)
            ...
            <b>at BatchJob.execute(BatchJob.groovy:49)</b>
            ...
    

    我尝试了以下操作来解决此问题,但都没有成功:

    • 我已经指定了 static fetchMode = [batchStatus: 'eager'] 在我的批处理域类上
    • 我已经用过 static mapping = { columns { batchStatus lazy:false }} 在我的批处理域类上
    • 我试过用 batch.attach() 打电话后 Batch.get() 在工作中

    我不能用 BatchJob.triggerNow() 在本例中,因为这只是几个示例中的一个-其他示例仍由服务调度,但可能被调度为cron作业或其他。我应该提到,我在升级Grails时也升级了Quartz插件;之前的Quartz版本是0.4.1-Snapshot(与升级版本相反,只有0.4.1)。

    如何使休眠会话在这些手动触发的石英作业中正常工作?

    我还将这个问题发送到了Grails用户邮件列表,对于这样一个更为利基的问题,列表似乎会引起更多的响应。如果有人出来,我会用答案来更新这个问题。 Here's a link .

    3 回复  |  直到 10 年前
        1
  •  0
  •   Rob Hruska MegalomanINA    15 年前

    查看JIRA第165期( http://jira.codehaus.org/browse/GRAILSPLUGINS-165 )Quartz插件中也有一些线索(您可能想查看一下),这段代码与JMS插件一起使用,看起来效果不错。

    尝试

        import org.hibernate.FlushMode
        import org.hibernate.Session
        import org.springframework.orm.hibernate3.SessionFactoryUtils
        import org.springframework.orm.hibernate3.SessionHolder
    
        class BatchJob implements Job, InterruptableJob
        {
            static triggers = {}
            void execute(JobExecutionContext context) {
               Session session = null;   
               try { 
                  session = SessionFactoryUtils.getSession(sessionFactory, false); 
               }
               // If not already bound the Create and Bind it! 
               catch (java.lang.IllegalStateException ex) { 
                  session = SessionFactoryUtils.getSession(sessionFactory, true);  
                  TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(session)); 
               }
              session.setFlushMode(FlushMode.AUTO);
              if( log.isDebugEnabled()) log.debug("Hibernate Session is bounded to Job thread");
    
            // Your Code!
            def batch = Batch.get(context.jobDetail.jobDataMap.getLongValue("batchId"))
            // the next line is "line 49" from the stack trace below
            def foo = batch.batchStatus.description
    
    
    
            try {
             SessionHolder sessionHolder = (SessionHolder) 
             TransactionSynchronizationManager.unbindResource(sessionFactory);
             if(!FlushMode.MANUAL.equals(sessionHolder.getSession().getFlushMode())) {
               sessionHolder.getSession().flush(); 
             }
             SessionFactoryUtils.closeSession(sessionHolder.getSession());
             if( log.isDebugEnabled()) log.debug("Hibernate Session is unbounded from Job thread and closed");
           }
           catch (Exception ex) { 
             ex.printStackTrace(); 
           }
       }
    }
    

    希望这有帮助。这对我很有用。

        2
  •  1
  •   Ilya Scharrenbroich    13 年前

    使用最新的Grails版本(Grails2.0.0)和可能更早的版本,您可以使用以下帮助方法来包装您的调用:

    class BatchJob implements Job, InterruptableJob
    {
      static triggers = {}
    
      void execute(JobExecutionContext context) {
        Batch.withSession { sess ->
          def batch = Batch.get(context.jobDetail.jobDataMap.getLongValue("batchId"))
          def foo = batch.batchStatus.description
        }
      }
    }
    
        3
  •  0
  •   Dmitriy rajalaxmi    10 年前

    我想你可以打电话来 attach() 方法向传递到计划作业的对象添加会话。

    job.attach()