在单个Hibernate会话(使用Spring)中进行多个事务

12
使用Hibernate + Spring能否模拟以下操作:

打开会话

  • 开始事务
  • 做一些工作
  • 提交
  • 开始另一个事务
  • 更多的工作
  • 提交
  • 关闭会话

我使用Spring TransactionTemplate来管理会话和事务的生命周期。

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

这可行吗?


你可以在不使用事务模板的情况下完成这个操作 - 使用 session.flush; session.clear; 命令,然后使用 session.refresh(object) 命令重新加载你的对象。 - Jan Schmidt
3
session.flush() 不会提交任何东西,它只是将数据写入数据库。 - JB Nizet
2个回答

6
是的,Hibernate的会话可以开始和提交多个事务。您需要做的是将打开的会话存储在某个地方,然后重复使用它。请注意,Session不是线程安全对象,但如果您确定它不会出现并发问题,您只需要使用TransactionSynchronizationUtils将会话绑定到线程资源上,然后在需要时解除绑定。您可以在这里找到一个示例here,或者您可以查看OSIV及其标准实现。
这是一件非常复杂的事情,更容易且更可取的是立即关闭会话并不重复使用它,因为它可能会带来麻烦:
  • 缓存中的对象不会自动清除,因此您的Session将增长到OutOfMemory。
  • 除非这些对象是脏的,否则Session中的对象不会被刷新,因此被其他用户更改的对象的机会越来越大。确保只有一个用户将更改可写对象。
  • 如果在其中一个步骤中发生异常,您必须确保关闭Session。在Session内发生异常后,此对象不可重用。
  • 如果事务回滚,Spring会清除Session,因此所有对象都变为分离状态。如果至少有一个事务回滚,请确保丢弃所有内容。

你需要做的是将打开的会话存储在某个地方,然后重复使用它。这听起来像是一场灾难的配方! - Alex Barnes
这就是 OSIV 的工作方式 ;) 但它不会在线程范围之外存储会话,这也是相对安全的来源。 - Stanislav Bashkyrtsev
我的观点是你的回答暗示了一种自制方法,即“只需将会话存储在某个地方”。但请注意,这正是 OSIV 的最终工作方式 :) - Alex Barnes
我认为楼主问的问题比请求范围更大,尽管他在问题中没有提到任何相关内容。 - Stanislav Bashkyrtsev

2
您可以使用OpenSessionInView模式来实现此操作。如果您在Servlet环境中工作(问题没有说明),Spring提供了一个javax.servlet.Filter实现,您可以使用它。这将确保您的Hibernate会话在整个请求期间保持打开状态,而不仅仅是在单个事务中。
class的Javadoc非常全面,可能是一个很好的起点。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接