Hibernate 3.0.1引入了SessionFactory.getCurrentSession()方法。它允许应用程序开发人员将当前会话的跟踪委托给Hibernate本身。这是一个相当简单的功能,但Hibernate的几乎所有用户都不得不自己实现,或者依赖于第三方工具来实现。让我们看看Hibernate是如何实现这一功能的,以及它可能有什么用处。
上下文范围
我说SessionFactory.getCurrentSession()代表应用程序开发人员跟踪当前会话。这究竟是什么意思?会话被认为是“当前”的上下文是什么?是事务!更具体地说,是一个JTA事务。
确定当前会话的范围的另一个维度是它属于哪个工厂。因为Hibernate在SessionFactory内部实现这一功能,所以当前会话天生由该工厂跟踪。在内部,SessionFactory维护一个以JTA事务为键的会话映射。由于映射是按需构建的,并且仅在getCurrentSession()调用期间使用,因此开销很小:如果您不使用此功能,则映射永远不会构建。
示例用法
想象一个简单的场景,协调三个DAO之间的努力
public Bid myExposedCmtEjbServiceMethod(Long itemId, Double amount) { ItemDAO itemDAO = new ItemDAO( getSessionFactory() ); BidDAO bidDAO = new BidDAO( getSessionFactory() ); UserDAO userDAO = new UserDAO( getSessionFactory() ); Item item = itemDAO.load( itemId ); User bidder = userDAO.load( getCurrentUsername() ); return bidDAO.create( item, amount, user ); }
每个DAO应该如何利用相同的会话来执行其工作?典型的模式是在该上下文中使用ThreadLocals或类似上下文存储(例如JBoss TransactionLocal)来维护当前会话。此外,我们如何知道何时清理当前会话呢?
实现这些功能的一般模式是定义一个“顶级”服务/方法作为服务控制器,该控制器负责在服务处理开始时打开会话,将其“绑定”到上下文存储(以便其他协作者可以找到它),并在服务处理结束时清理会话。对这个模式的一个小变化是使用方法拦截来在“服务控制器”方法上应用这些行为(或方面)。无论如何,这都需要大量的设置工作,需要我们或者
- 修改所有服务控制器以执行打开-绑定-清理功能
- 将我们的所有服务(有时可能是意外地)包装在代理中,以便我们可以拦截方法执行并应用这些行为方面
因此,让我们看看使用SessionFactory.getCurrentSession()方法的方法
public class ItemDAO { private SessionFactory sf; public ItemDAO(SessionFactory sf) { this.sf = sf; } public Item load(Long itemId) { return ( Item ) sf.getCurrentSession().load( Item.class, itemId ); } ... }
在这里,每个DAO合作者只需简单地使用getCurrentSession()方法;与DAO合作的事物无需执行任何额外的操作,我们也不需要生成代理和拦截方法来应用上下文会话的概念。
因此,现在,通过使用getCurrentSession(),我们可以轻松地将当前会话的概念限定于JTA事务,并在整个JTA事务中重用相同的会话。但我们如何清理会话?以及我们如何管理会话状态与数据库的刷新呢?
自动刷新和关闭
Hibernate3引入的两个新配置选项非常强大,尤其是在与SessionFactory.getCurrentSession()结合使用时。这两个选项在JTA环境中以及应用程序使用Hibernate事务抽象API的场景中都是可用的。
第一个是flush_before_completion,它强制在事务完成之前刷新会话(想想Synchronization.beforeCompletion()...)。启用此设置后,我们无需担心在完成操作后刷新会话以同步内存状态与数据库;Hibernate会为我们完成(就在事务提交之前)。
第二个是auto_close_session,它强制在事务完成后关闭会话。在JTA环境中,此设置还有一个额外效果;它强制Hibernate更加积极地释放JDBC连接。基本上,Hibernate会获取一个连接,使用它,然后立即将其释放回数据源。这允许更好地集成到实现某种形式的连接封装
检查的JTA环境中(例如,JBoss CachedConnectionManager)。
结论
所有这些加在一起,让应用程序开发者能够从管理会话生命周期
中解放出来,由Hibernate来替他们管理。