Grails Quartz Job升级后没有Hibernate会话,导致LazyInitializationException

发布于 2024-08-13 23:48:29 字数 2757 浏览 12 评论 0原文

我已将 Grails 1.0.4 应用程序升级到 1.1.1。升级后,在执行 Quartz 作业(使用 Quartz 插件 0.4.1)时,我反复出现异常。该插件用于通过服务使用 Simple 和 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)
    }
    ...
}

我的 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 域类上,
  • 我在我的 Batch 域类上使用了 static mapping = { columns { batchStatus lazy:false }}
  • 我尝试使用 batch.attach() 在作业中调用 Batch.get() 后,

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

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

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

I've upgraded a Grails 1.0.4 application to 1.1.1. After upgrading, I'm repeatedly getting Exceptions when executing my Quartz jobs (using Quartz plugin 0.4.1). The plugin is used to manually schedule jobs using Simple and Cron Triggers via a service (paraphrased code below):

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

My BatchJob job is set up as follows:

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

Here's an abbreviated definition of Batch.groovy (domain):

class Batch
{
    BatchStatus batchStatus // relationship
}

However, when schedulerService.schedule() is invoked with an existing, saved Batch, I receive the following Exception:

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

I've tried the following actions to fix this, but none have worked:

  • I've specified static fetchMode = [batchStatus: 'eager'] on my Batch domain class
  • I've used static mapping = { columns { batchStatus lazy:false }} on my Batch domain class
  • I've tried using batch.attach() after calling Batch.get() in the Job

I can't use BatchJob.triggerNow() in this instance, because this is only one of a couple examples - the others are still scheduled by the service, but might be scheduled as a cron job or otherwise. I should mention that I did upgrade the Quartz plugin as well when upgrading Grails; the previous Quartz version was 0.4.1-SNAPSHOT (as opposed to the upgraded version, just 0.4.1).

How do I get Hibernate sessions to work correctly in these manually-triggered Quartz Jobs?

I've also sent this question to the grails-user mailing list, as for a more niche issue like this, the list seems to elicit a bit more response. I'll update this question with an answer if one comes out of there. Here's a link.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

清晨说晚安 2024-08-20 23:48:29

使用最新的 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
    }
  }
}

With the latest grails version (Grails 2.0.0) and maybe earlier versions, you can just wrap your call with this helper method:

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
    }
  }
}
稚然 2024-08-20 23:48:29

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

job.attach()

I think you can call attach() method to add session to the object passing to the scheduled job.

job.attach()
扬花落满肩 2024-08-20 23:48:29

查看 jira 问题 165 (http://jira.codehaus.org/browse/GRAILSPLUGINS-165< /a>)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(); 
       }
   }
}

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

Check out jira issue 165 (http://jira.codehaus.org/browse/GRAILSPLUGINS-165) There are also clues in the Quartz Plugin (which you may like to check out) This code was used with the JMS plugin which seems to work well.

try

    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(); 
       }
   }
}

Hope this helps. It worked for me.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文