单个休眠会话中的多个事务(使用 Spring)

Posted

技术标签:

【中文标题】单个休眠会话中的多个事务(使用 Spring)【英文标题】:Multiple transactions in a single hibernate session (with Spring) 【发布时间】:2012-11-11 22:32:10 【问题描述】:

是否可以使用 Hibernate + Spring 对以下内容进行建模。

打开会话 开始交易 做一些工作 提交 开始交易 更多工作 提交 关闭会话

我使用 Spring TransactionTemplate,它同时执行会话 + 事务生命周期范围。

原因是有时我在业务流程中有几个阶段,我想在每个阶段完成后提交。但是我想继续使用相同的持久对象。如果我每个事务都有一个单独的会话,那么我会收到暂时/分离的异常,因为原始会话已关闭。

这可能吗?

【问题讨论】:

您可以在没有事务模板的情况下执行此操作 - 使用 session.flush; session.clear;用 session.refresh(object) 重新加载你的对象 session.flush() 不提交任何内容。它只是写入数据库。 【参考方案1】:

是的,Hibernate 的会话可以开始并提交多个事务。您需要做的是将打开的会话存储在某处,然后重用它。注意,Session 不是线程安全的对象,但是如果你确定它不会有并发问题,你只需要使用TransactionSynchronizationUtils 将会话绑定到线程资源,然后在如果需要,您可以找到一个示例 here,或者您可以查看 OSIV 及其标准实现。

这是一个非常复杂的事情,它会容易得多,因此最好立即关闭会话并且不要重复使用它,因为它可能会带来麻烦:

缓存内的对象不会被自动驱逐,因此您的 Session 会增长到 OutOfMemory。 会话内部的对象不会被刷新,除非它们是脏的,因此对象被另一个用户更改的机会越来越大。确保只有一个用户会更改可写对象。 如果在某一步骤中发生异常,您必须确保关闭会话。 Session 内部发生异常后,该对象不可重用。 如果事务回滚,则 Spring 会清除会话,因此您的所有对象都将分离。如果至少有一个事务被回滚,请确保丢弃所有内容。

【讨论】:

"你需要做的是将打开的会话存储在某个地方,然后重用它。"这听起来像是灾难的秘诀! 这就是 OSIV 的工作方式;)但它不会将会话存储在线程范围之外,这就是相对安全性的来源。 我的意思是,您的回答暗示了一种“仅将会话存储在某处”的自制方法。欣赏这就是 OSIV 最终的工作方式:) 我认为主题启动者正在询问比请求范围更大的内容,但他在问题中没有提及任何内容..【参考方案2】:

您可以使用 OpenSessionInView 模式来实现这一点。 Spring 提供了一个 javax.servlet.Filter 实现,如果您在 servlet 环境中工作,您可以使用它(问题没有这么说)。这将确保您的 Hibernate 会话在请求期间保持打开状态,而不仅仅是单个事务。

class 上的 Javadoc 非常全面,可能是一个很好的起点。

【讨论】:

以上是关于单个休眠会话中的多个事务(使用 Spring)的主要内容,如果未能解决你的问题,请参考以下文章

如何在休眠中处理多个会话事务提交和回滚?

带有 2 个数据库的休眠随机“会话已关闭错误”

使用 Spring Boot 在单个浏览器会话中使用多个 OAuth2 客户端

从休眠中的会话中删除对象? [复制]

您如何测试 Spring @Transactional 而不只是命中休眠级别 1 缓存或进行手动会话刷新?

spring boot 1.5.1.RELEASE 问题与休眠会话工厂创建有关