当前(上下文)会话

发布    |      

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来替他们管理。


回到顶部