ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
# 11.2.2\. 使用JTA 如果你的持久层运行在一个应用服务器中(例如,在EJB session beans的后面),Hibernate获取 的每个数据源连接将自动成为全局JTA事务的一部分。 你可以安装一个独立的JTA实现,使用它而不使用EJB。Hibernate提供了两种策略进行JTA集成。 如果你使用bean管理事务(BMT),可以通过使用Hibernate的 `Transaction` API来告诉 应用服务器启动和结束BMT事务。因此,事务管理代码和在非托管环境下是一样的。 ``` // BMT idiom Session sess = factory.openSession(); Transaction tx = null; try { tx = sess.beginTransaction(); // do some work ... tx.commit(); } catch (RuntimeException e) { if (tx != null) tx.rollback(); throw e; // or display error message } finally { sess.close(); } ``` 如果你希望使用与事务绑定的`Session`,也就是使用`getCurrentSession()`来简化上下文管理,你将不得不直接使用JTA `UserTransaction`API。 ``` // BMT idiom with getCurrentSession() try { UserTransaction tx = (UserTransaction)new InitialContext() .lookup("java:comp/UserTransaction"); tx.begin(); // Do some work on Session bound to transaction factory.getCurrentSession().load(...); factory.getCurrentSession().persist(...); tx.commit(); } catch (RuntimeException e) { tx.rollback(); throw e; // or display error message } ``` 在CMT方式下,事务声明是在session bean的部署描述符中,而不需要编程。 因此,代码被简化为: ``` // CMT idiom Session sess = factory.getCurrentSession(); // do some work ... ``` 在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环境中有一个弊端。对`after_statement`连接释放方式有一个警告,这是被默认使用的。因为JTA规范的一个很愚蠢的限制,Hibernate不可能自动清理任何未关闭的`ScrollableResults` 或者`Iterator`,它们是由`scroll()`或`iterate()`产生的。你_must_通过在`finally`块中,显式调用`ScrollableResults.close()`或者`Hibernate.close(Iterator)`方法来释放底层数据库游标。(当然,大部分程序完全可以很容易的避免在JTA或CMT代码中出现`scroll()`或`iterate()`。)