我正在 Grails 中编写一个多线程应用程序,其他线程需要访问 GORM/Hibernate。当他们尝试访问 GORM 时,我收到错误“org.hibernate.HibernateException:没有绑定到线程的 Hibernate 会话,并且配置不允许在此处创建非事务性会话”。
好吧,公平地说,有人可以指导我设置线程以进行访问的最佳方式吗?错误消息听起来就像您只需要更改一些配置选项,但我感觉,它并不那么简单......
我正在 Grails 中编写一个多线程应用程序,其他线程需要访问 GORM/Hibernate。当他们尝试访问 GORM 时,我收到错误“org.hibernate.HibernateException:没有绑定到线程的 Hibernate 会话,并且配置不允许在此处创建非事务性会话”。
好吧,公平地说,有人可以指导我设置线程以进行访问的最佳方式吗?错误消息听起来就像您只需要更改一些配置选项,但我感觉,它并不那么简单......
您需要将任何 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 )
}
Grails 应用程序中有一个名为“persistenceInterceptor”的 bean 可用于此目的。
请参阅 JMS 插件中的此示例以了解如何使用它:
这是界面:
和休眠实现:
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
}
}
卢克戴利给出了正确的答案。不幸的是,链接已更改。因此,我将更新他的答案并提供一个代码示例以使该答案自成一体。
Grails 应用程序中有一个名为的 bean persistenceInterceptor
,可用于初始化 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 上找到。