如何将 Hibernate Session 绑定到 Grails 中的线程?

Posted

技术标签:

【中文标题】如何将 Hibernate Session 绑定到 Grails 中的线程?【英文标题】:How to I bind a Hibernate Session to a thread in Grails? 【发布时间】:2011-04-03 03:53:33 【问题描述】:

我正在 Grails 中编写一个多线程应用程序,其他线程需要访问 GORM/Hibernate。当他们尝试访问 GORM 时,我收到错误“org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allowed create non-transactional one here”。

好吧,公平地说,有人可以指导我设置线程以进行访问的最佳方式吗?错误消息听起来就像您只需要更改一些配置选项,但我感觉,它并不那么简单......

【问题讨论】:

【参考方案1】:

Grails 应用程序中有一个名为“persistenceInterceptor”的 bean 可用于此目的。

请参阅 JMS 插件中的此示例以了解如何使用它:

http://github.com/gpc/grails-jms/blob/master/src/groovy/grails/plugin/jms/listener/adapter/PersistenceContextAwareListenerAdapter.groovy#L21

界面如下:

https://github.com/grails/grails-core/blob/master/grails-core/src/main/groovy/grails/persistence/support/PersistenceContextInterceptor.java

Hibernate 实现:

https://github.com/grails/grails-data-mapping/blob/master/grails-datastore-gorm-support/src/main/groovy/org/grails/orm/hibernate4/support/HibernatePersistenceContextInterceptor.java

【讨论】:

第二个链接坏了,是不是位置变了?【参考方案2】:

您需要将任何 GORM 调用放入 withTransaction 闭包中。一个例子取自多线程的讨论 https://fbflex.wordpress.com/2010/06/11/writing-batch-import-scripts-with-grails-gsql-and-gpars/

单线程

user = User.findByUsername( photo.username )

多线程

User.withTransaction
user = User.findByUsername( photo.username )

【讨论】:

这可能是偶尔线程使用最简单的方法了。【参考方案3】:

withNewSession 也可以。就我而言,我的更新优先级较低,最后一次更新总是可以“获胜”。 version: false 在这里也很重要,以避免 StaleObjectException:

     Thread.start 
        try 
            Widget.withNewSession 
                xxx()
                log.info "Asynchronously did some updates."
            
         catch (Exception ex) 
            log.error "Failed to asynchronously do something...", ex
        
    

【讨论】:

这是我一直在寻找的答案。 方式比使用 withTransaction 更好,如果您在后台进行一些您希望在进行时显示的更新。【参考方案4】:

Luke Daley 给出了正确答案。不幸的是,链接已更改。因此,我将更新他的答案并提供一个代码示例以使此答案自包含。

Grails 应用程序中有一个名为persistenceInterceptor 的bean,可用于为Hibernate 初始化持久性上下文/会话。您可以将 bean 注入您的控制器/服务类之一并启动一个新线程,例如使用以下代码 sn-p。

class YourControllerOrService 
    PersistenceContextInterceptor persistenceInterceptor
    
    def someOperation() 
        ...
        Runnable yourTask =  ->
            try 
                if (persistenceInterceptor) 
                    persistenceInterceptor.init()
                
            
                // execute the hibernate operations here in a transaction,
                // e.g. call a method annotated with @Transactional
                ...
             catch (Exception e) 
                    log.error('Your error message', e)
             finally 
                if (persistenceInterceptor) 
                    persistenceInterceptor.flush()
                    persistenceInterceptor.destroy()
                
            
        
        Thread workerThread = new Thread(yourTask)
        workerThread.start()
        ...
    

您将在 Grails JMS plug-in on GitHub 中找到示例性实现。

PersistenceContextInterceptor 接口也可以在 GitHub 上找到。

【讨论】:

以上是关于如何将 Hibernate Session 绑定到 Grails 中的线程?的主要内容,如果未能解决你的问题,请参考以下文章

没有 Hibernate Session 绑定到线程,并且配置不允许在这里创建非事务性会话

Hibernate绑定session保证session为单线程操作

hibernate中的事物问题放在业务层

[原创]java WEB学习笔记94:Hibernate学习之路---session 的管理,Session 对象的生命周期与本地线程绑定

Hibernate中Session与本地线程绑定

hibernate之绑定本地session