11.2.2. 使用JTA

如果你的持久层运行在一个应用服务器中(例如,在EJB session beans的后面),Hibernate获取 的每个数据源连接将自动成为全局JTA事务的一部分。 你可以安装一个独立的JTA实现,使用它而不使用EJB。Hibernate提供了两种策略进行JTA集成。

如果你使用bean管理事务(BMT),可以通过使用Hibernate的 Transaction API来告诉 应用服务器启动和结束BMT事务。因此,事务管理代码和在非托管环境下是一样的。

  1. // BMT idiom
  2. Session sess = factory.openSession();
  3. Transaction tx = null;
  4. try {
  5. tx = sess.beginTransaction();
  6. // do some work
  7. ...
  8. tx.commit();
  9. }
  10. catch (RuntimeException e) {
  11. if (tx != null) tx.rollback();
  12. throw e; // or display error message
  13. }
  14. finally {
  15. sess.close();
  16. }

如果你希望使用与事务绑定的Session,也就是使用getCurrentSession()来简化上下文管理,你将不得不直接使用JTA UserTransactionAPI。

  1. // BMT idiom with getCurrentSession()
  2. try {
  3. UserTransaction tx = (UserTransaction)new InitialContext()
  4. .lookup("java:comp/UserTransaction");
  5. tx.begin();
  6. // Do some work on Session bound to transaction
  7. factory.getCurrentSession().load(...);
  8. factory.getCurrentSession().persist(...);
  9. tx.commit();
  10. }
  11. catch (RuntimeException e) {
  12. tx.rollback();
  13. throw e; // or display error message
  14. }

在CMT方式下,事务声明是在session bean的部署描述符中,而不需要编程。 因此,代码被简化为:

  1. // CMT idiom
  2. Session sess = factory.getCurrentSession();
  3. // do some work
  4. ...

在CMT/EJB中甚至会自动rollback,因为假若有未捕获的RuntimeException从session bean方法中抛出,这就会通知容器把全局事务回滚。这就意味着,在BMT或者CMT中,你根本就不需要使用Hibernate Transaction API ,你自动得到了绑定到事务的“当前”Session。

注意,当你配置Hibernate的transaction factory的时候,在直接使用JTA的时候(BMT),你应该选择org.hibernate.transaction.JTATransactionFactory,在CMT session bean中选择org.hibernate.transaction.CMTTransactionFactory。记得也要设置hibernate.transaction.manager_lookup_class。还有,确认你的hibernate.current_session_context_class未设置(为了向下兼容),或者设置为"jta"

getCurrentSession()在JTA环境中有一个弊端。对afterstatement连接释放方式有一个警告,这是被默认使用的。因为JTA规范的一个很愚蠢的限制,Hibernate不可能自动清理任何未关闭的ScrollableResults 或者Iterator,它们是由scroll()iterate()产生的。你_must通过在finally块中,显式调用ScrollableResults.close()或者Hibernate.close(Iterator)方法来释放底层数据库游标。(当然,大部分程序完全可以很容易的避免在JTA或CMT代码中出现scroll()iterate()。)