在grails中的后台线程中调用Hibernate

时间:2011-08-25 05:32:36

标签: hibernate grails groovy

我正在尝试在grails应用程序中创建特定类型的后台处理设置。

  • 固定尺寸​​线程池仅在作业批次期间存在
  • 每个帖子都维护单个会话
  • 每个作业都在单独交易
  • 中运行

我正在尝试按如下方式开始工作:

int poolSize = 10
ThreadFactory factory = new MyThreadFactory (Executors.defaultThreadFactory())
ExecutorService pool = Executors.newFixedThreadPool (poolSize, factory)

(1..100).each { i ->
  pool.submit {
    try {
      MyDomainClass.withTransaction {
        doSomeWork(i)
      }
    } catch (Exception e) {
      log.error "error in job ${i}", e
    }
  }
}

MyThreadFactory 会创建在线程持续时间内附加 hibernate会话的线程。

class MyThreadFactory implements ThreadFactory {

  ThreadFactory delegate
  PersistenceContextInterceptor persistenceInterceptor

  MyThreadFactory (ThreadFactory delegate) {
    this.delegate = delegate
    ApplicationContext applicationContext = ApplicationHolder.getApplication().getMainContext()
    persistenceInterceptor = applicationContext.getBean("persistenceInterceptor");
  }

  Thread newThread (Runnable work) {
    return delegate.newThread {
      persistenceInterceptor.init()
      try {
        work.run()
      } finally {
        persistenceInterceptor.flush()
        persistenceInterceptor.destroy()
      }
    }
  }
}

它似乎工作,但是我第一次运行批处理作业时会出现以下错误。 (后续工作无故障运行)

groovy.lang.MissingMethodException: No signature of method: static MyDomainClass.save() is applicable for argument types: (java.util.LinkedHashMap) values: [[flush:false]]
Possible solutions: save(), save(java.util.Map), save(java.lang.Boolean), wait(), any(), wait(long)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at ...

我尝试用 MyDomainClass.withNewSession {} 替换persitanceInterceptor,但没有效果。

好像GORM方法没有被注入到我的域类中。

任何人都可以看到我做错了什么,为什么再次运行批处理作业可以让它成功?

@fixitagain 为了完整起见,这项工作采用以下形式:

 doSomeWork = { id ->
    MyDomainClass a = MyDomainClass.findById (id)
    a.value = lotsOfWork()
    a.save()
 }

我相信丢失的保存是一个红色的鲱鱼,因为我尝试在事务中包装操作,然后得到一个错误,说“DomainClass.withTransaction(Closure)”没有定义。

看起来可能存在第一个作业无法运行的竞争条件,但所有后续作业在(某些内容?)启动后成功运行。

3 个答案:

答案 0 :(得分:1)

可能建议使用Grails的executor插件,而不是尝试创建自己的线程。它为你创建的线程注入了必要的hibernate会话,也可以根据它使用的执行器,线程数等进行配置。我在石英作业和其他场景的生产中使用它,它工作得很好。

Grails Executor Plugin 如果您对使用它有所保留,可以在编写自己的线程策略之前查看其代码。

答案 1 :(得分:0)

我无法从代码或命名约定中得出结论,但您确定要在域类的实例上调用save吗?

答案 2 :(得分:0)

缺少方法异常意味着您在Class上调用save,而不是实例。

编辑:GORM已经应用了其他方法,您可以在建议的解决方法方法名称中看到。