Steve刚刚向Hibernate Core提交了一个新的接口和扩展点。我们终于可以将自定义会话上下文管理插入到Hibernate中。对于那些已经了解getCurrentSession()在Hibernate 3.0中的人来说,这个新扩展使得同样的功能在没有JTA环境的情况下也能实现。

但是它是如何工作的呢?在J2EE容器中,我们可以依赖于当前JTA事务的作用域来绑定Hibernate Session。所以每次当你调用getCurrentSession()时,你得到的就是这个。然而,在容器之外,我们实际上不知道会话何时结束(开始是很容易的:第一次请求一个会话)。

因此,需要一个新接口,允许Hibernate用户提供《q>当前会话。事实上,这个接口CurrentSessionContext正好有这个你可以实现的单个方法。但你不一定需要这样做,Hibernate 3.1附带两个默认实现。

  • 对于JTA环境而言的常规行为,将当前会话绑定到当前系统事务。这不需要任何额外配置,只需将Hibernate设置为用于管理的J2EE使用(事务管理器等),并调用sessionFactory.getCurrentSession()。不需要刷新或关闭会话。如果你使用CMT,事务边界是声明性的,如果你使用BMT,请在当前会话上调用beginTransaction(), getTransaction().commit()getTransaction().rollback()。如果你想要,可以通过设置新的属性current_session_context_class"jta"来在你的Hibernate配置中启用JTA上下文管理,但再次提醒,如果Hibernate已配置为用于J2EE,则这是默认设置。
  • 对于非管理环境中的典型Hibernate部署的实现,将当前会话绑定到当前线程。然而,此实现需要你的一点点帮助来标记工作单元的结束(我们无法等待线程结束)。你必须调用静态方法ThreadLocalSessionContext.unbind().close()从线程中删除当前会话并关闭它。要启用此上下文处理器,请设置current_session_context_class配置属性为"thread".

当然,你可以实现自己的CurrentSessionContext并在配置中命名该类,例如,使用EJB实现长会话(或在新术语中:扩展持久化上下文)模式,在请求和JTA事务之间将断开连接的会话存储在SFSB中。

传统的HibernateUtil类现在最终可以简化为一个简单的启动辅助工具,用于初始化一个SessionFactory。这就是在CMT、BMT和非JTA环境中,典型的数据访问程序现在的样子。

Session s = HibernateUtil.getSessionFactory().getCurrentSession();
s.beginTransaction();
    
s.save(item); // or
HibernateUtil.getSessionFactory().getCurrentSession().save(item);
    
s.getTransaction().commit();

ThreadLocalSessionContext.unbind().close(); // Only needed for non-JTA

使用HibernateUtil,我们并不关心SessionFactory来自哪里,无论是静态单例还是来自JNDI。最后一行仅用于在应用服务器外部的内置“线程”上下文处理,如上所述。其余的代码在所有部署情况下都是相同的。通常,您会在某种类型的拦截器中解绑并关闭会话,并在知道请求处理完成时的一些系统类中封装最后一行。这两行保存项的代码是等效的,这里的目的在于向您展示您可以在任何您喜欢的(DAO)类中多次调用getCurrentSession()

对于那些不想从CVS构建Hibernate来尝试这个新功能的人:我已经准备了一个更新的CaveatEmptor版本,其中包含从CVS的Hibernate 3.1快照,更新的HibernateUtil和更新的DAO/单元测试类。其他Hibernate文档(以及关于Session处理的流行Wiki页面)将在实际的3.1版本可用时更新。


回到顶部