1

我已将 Grails 1.0.4 应用程序升级到 1.1.1。升级后,我在执行 Quartz 作业(使用 Quartz 插件 0.4.1)时反复出现异常。该插件用于通过服务使用 Simple 和 Cron Triggers 手动安排作业(解释代码如下):

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)
    }
    ...
}

我的 BatchJob 作业设置如下:

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']在我的 Batch 域类中指定
  • static mapping = { columns { batchStatus lazy:false }}在我的 Batch 域类上使用过
  • batch.attach()在调用Batch.get()Job后尝试使用

我不能BatchJob.triggerNow()在这种情况下使用,因为这只是几个示例之一 - 其他示例仍由服务安排,但可能被安排为 cron 作业或其他方式。我应该提一下,我在升级 Grails 时也升级了 Quartz 插件;之前的 Quartz 版本是 0.4.1-SNAPSHOT(相对于升级版,只有 0.4.1)。

如何让 Hibernate 会话在这些手动触发的 Quartz 作业中正常工作?

我还将这个问题发送到 grails-user 邮件列表,至于像这样的更小众问题,该列表似乎引起了更多的响应。如果有人从那里出来,我会用答案更新这个问题。这是一个链接

4

3 回答 3

1

使用最新的 grails 版本(Grails 2.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
    }
  }
}
于 2012-04-16T01:44:09.200 回答
1

我认为您可以调用attach()方法将会话添加到传递给计划作业的对象。

job.attach()
于 2015-04-03T10:35:53.080 回答
0

查看 jira 问题 165 ( http://jira.codehaus.org/browse/GRAILSPLUGINS-165 ) Quartz Plugin 中也有线索(您可能想查看) 此代码与 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(); 
       }
   }
}

希望这可以帮助。它对我有用。

于 2009-12-07T21:42:15.137 回答