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

标签 hibernate grails groovy

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

  • 一个 固定大小线程池 仅在 期间存在批作业的
  • 一个 单个 session 由每个线程维护
  • 每个作业都在 中运行单独交易

  • 我正在尝试按如下方式开始工作:
    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
        }
      }
    }
    

    我的线程工厂 创建具有 的线程附加 hibernate session 在线程的持续时间内。
    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 ...
    

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

    看起来好像 GORM 方法没有被注入(inject)到我的域类中。

    谁能看到我做错了什么,为什么再次运行批处理作业可以成功?

    @fixitagain 为了完整起见,工作采用以下形式:
     doSomeWork = { id ->
        MyDomainClass a = MyDomainClass.findById (id)
        a.value = lotsOfWork()
        a.save()
     }
    

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

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

    最佳答案

    与其尝试创建自己的线程,不如使用 Grails 的执行器插件。它将必要的 hibernate session 注入(inject)到您创建的线程中,它还可以根据它使用的执行器、线程数等进行配置。我在生产中使用它来处理 quartz 作业和其他场景,它工作得很好。
    Grails Executor Plugin
    如果您对使用它有所保留,您可以在编写自己的线程策略之前查看它的代码。

    关于hibernate - 在 grails 的后台线程中调用 Hibernate,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7185567/

    相关文章:

    Grails 3.x 和 Jenkins : Save BUILD_NUMBER and date when deploying

    xml - Grails/Groovy - 将对象呈现/直接转换为 XML 以保存到文件

    grails - 如何处理 groovy 方法中的多个返回类型?

    grails - Grails 2.4.4与Java 8的兼容性

    java - Hibernate Jsp Servlet 注册表单不起作用

    java - 从 Hibernate 生成 SWING/Gui

    java - Hibernate session 关闭异常,当10个或更多用户访问页面时

    hibernate - 将原生 SQL 查询的结果映射到 Grails 域类

    java - 如何在 list 中多次检入GSP Grails

    java - Groovy - 不明确的处理程序方法