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