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

发布于 2024-09-15 09:57:49 字数 232 浏览 12 评论 0原文

我正在用 Grails 编写一个多线程应用程序,附加线程需要访问 GORM/Hibernate。当他们尝试访问 GORM 时,我收到错误“org.hibernate.HibernateException:没有 Hibernate 会话绑定到线程,并且配置不允许在此处创建非事务会话”。

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

I'm writing a multi-threaded application in Grails and the additional threads need access to GORM/Hibernate. When they try to access GORM I get the error "org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here".

OK fair enough, can someone guide me on the best way to set the threads up to have access? The error message almost sounds like you just need to change some config options yet I sense, it is not so simple...

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

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

发布评论

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

评论(4

野稚 2024-09-22 09:57:49

您需要将任何 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 )
}

You need to put any GORM calls in a withTransaction closure. An example taken from a discussion of multi threading at
https://fbflex.wordpress.com/2010/06/11/writing-batch-import-scripts-with-grails-gsql-and-gpars/

Single threaded

user = User.findByUsername( photo.username )

multi threaded

User.withTransaction{
user = User.findByUsername( photo.username )
}
记忆消瘦 2024-09-22 09:57:49

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

withNewSession will also work. In my case, I have low priority updates where the last update can always "win". version: false is also important here in order to avoid the StaleObjectException:

     Thread.start {
        try {
            Widget.withNewSession {
                xxx()
                log.info "Asynchronously did some updates."
            }
        } catch (Exception ex) {
            log.error "Failed to asynchronously do something...", ex
        }
    }
咿呀咿呀哟 2024-09-22 09:57:49

卢克·戴利给出了正确的答案。不幸的是,链接已更改。因此,我将更新他的答案并提供一个代码示例以使该答案独立。

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

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

您将在 GitHub 上的 Grails JMS 插件

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

Luke Daley gave the right answer. Unfortunately, the links have changed. Thus, I'll update his answer and provide a code example to make this answer self-contained.

There is a bean in Grails applications called persistenceInterceptor that can be used for initializing the persistence context / session for Hibernate. You can inject the bean into one of your controller / service classes and start a new thread, e.g. using the following code snippet.

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

You'll find an exemplary implementation in the Grails JMS plug-in on GitHub.

The PersistenceContextInterceptor interface can be found on GitHub, too.

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