12.2.1.非托管环境
如果Hibernat持久层运行在一个非托管环境中,数据库连接通常由Hibernate的连接池机制 来处理。
代码内容
session/transaction处理方式如下所示:
//Non-managed environment 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();
}
你不需要显式flush() Session - 对commit()的调用会自动触发session的同步。
调用 close() 标志session的结束。 close()方法重要的暗示是,session释放了JDBC连接。
这段Java代码是可移植的,可以在非托管环境和JTA环境中运行。
你很可能从未在一个标准的应用程序的业务代码中见过这样的用法;致命的(系统)异常应该总是 在应用程序“顶层”被捕获。换句话说,执行Hibernate调用的代码(在持久层)和处理 RuntimeException异常的代码(通常只能清理和退出应用程序)应该在不同 的应用程序逻辑层。这对于你设计自己的软件系统来说是一个挑战,只要有可能,你就应该使用 J2EE/EJB容器服务。异常处理将在本章稍后进行讨论。
请注意,你应该选择 org.hibernate.transaction.JDBCTransactionFactory (这是默认选项).
12.2.2.使用JTA
如果你的持久层运行在一个应用服务器中(例如,在EJB session beans的后面),Hibernate获取 的每个数据源连接将自动成为全局JTA事务的一部分。Hibernate提供了两种策略进行JTA集成。
如果你使用bean管理事务(BMT),可以通过使用Hibernate的 Transaction API来告诉 应用服务器启动和结束BMT事务。因此,事务管理代码和在非托管环境下是一样的。
代码内容
在CMT方式下,事务声明是在session bean的部署描述符中,而不需要编程。 除非你设置了属性hibernate.transaction.flush_before_completion和 hibernate.transaction.auto_close_session为true, 否则你必须自己同步和关闭Session。Hibernate可以为你自动同步和关闭 Session。你唯一要做的就是当发生异常时进行事务回滚。幸运的是, 在一个CMT bean中,事务回滚甚至可以由容器自动进行,因为由session bean方法抛出的未处理的 RuntimeException异常可以通知容器设置全局事务回滚。这意味着 在CMT中,你完全无需使用Hibernate的Transaction API 。
// 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();
}
请注意,当你配置Hibernate事务工厂的时候,在一个BMT session bean中,你应该选择 org.hibernate.transaction.JTATransactionFactory,在一个 CMT session bean中选择org.hibernate.transaction.CMTTransactionFactory。 记住,同时也要设置org.hibernate.transaction.manager_lookup_class。
如果你使用CMT环境,并且让容器自动同步和关闭session,你可能也希望在你代码的不同部分使用 同一个session。一般来说,在一个非托管环境中,你可以使用一个ThreadLocal 变量来持有这个session,但是单个EJB方法调用可能会在不同的线程中执行(举例来说,一个session bean调用另一个session bean)。如果你不想在应用代码中被传递Session对 象实例的问题困扰的话,那么SessionFactory 提供的 getCurrentSession()方法就很适合你,该方法返回一个绑定到JTA事务 上下文环境中的session实例。这也是把Hibernate集成到一个应用程序中的最简单的方法!这个“当 前的”session总是可以自动同步和自动关闭(不考虑上述的属性设置)。我们的session/transaction 管理代码减少到如下所示:
代码内容
// CMT idiom
Session sess = factory.getCurrentSession();
// do some work
...
换句话来说,在一个托管环境下,你要做的所有的事情就是调用 SessionFactory.getCurrentSession(),然后进行你的数据访问,把其余的工作 交给容器来做。事务在你的session bean的部署描述符中以可声明的方式来设置。session的生命周期完全 由Hibernate来管理。
对after_statement连接释放方式有一个警告。因为JTA规范的一个很愚蠢的限制,Hibernate不可能自动清理任何未关闭的ScrollableResults 或者Iterator,它们是由scroll()或iterate()产生的。你must通过在finally块中,显式调用ScrollableResults.close()或者Hibernate.close(Iterator)方法来释放底层数据库游标。(当然,大部分程序完全可以很容易的避免在CMT代码中出现scroll()或iterate()。)