我正在用 Grails 编写一个多线程应用程序,附加线程需要访问 GORM/Hibernate。当他们尝试访问 GORM 时,我收到错误“org.hibernate.HibernateException:没有 Hibernate 会话绑定到线程,并且配置不允许在此处创建非事务会话”。
好吧,公平地说,有人可以指导我设置线程以进行访问的最佳方法吗?错误消息听起来几乎像是您只需要更改一些配置选项,但我感觉,事情并不那么简单......
Grails 应用程序中有一个名为“persistenceInterceptor”的 bean 可以用于此目的。
请参阅 JMS 插件中的示例了解如何使用它:
这是界面:
和 Hibernate impl:
您需要将任何 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 )
}
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 应用程序中有一个名为
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 上找到。