单个休眠会话中的多个事务(使用 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)的主要内容,如果未能解决你的问题,请参考以下文章
使用 Spring Boot 在单个浏览器会话中使用多个 OAuth2 客户端