在JSF web应用程序中使用延迟加载时的Hibernate会话处理



Javaworld Get started with Hibernate教程说明:

Session的实例是轻量级的,创建和销毁都很便宜。这一点很重要,因为您的应用程序将始终需要创建和销毁会话,可能是针对每个请求。Hibernate会话不是线程安全的,按照设计一次只能由一个线程使用。

因为Tomcat在多个线程中处理HTTP请求,所以线程安全在web应用中是非常必要的。因此,我读到这个答案:

会话应该是每个方法的局部变量。通过这样做,DAO将变成无状态的,因此本质上是线程安全的,不需要任何同步

让我们在基于JSF的web应用程序中以这种方式实现它:

private static final SessionFactory sessionFactory;
public Object read(Class c, Integer id){
    try{
        Session session = sessionFactory.openSession();
        return session.get(c, id);
    }finally{
        session.close();
    }
}

当涉及到延迟加载时,你肯定会得到一个LazyInitializationException,几分钟或几小时后,一些用户交互需要访问一个对象的延迟加载集合,这个对象存储在用户会话中,并且是用上面的代码从Hibernate读取的,因为用于加载它的会话很久以前就关闭了。(我不认为避免延迟加载是一个解决方案,这是最常见的建议。)

继续往下看,我还发现:

您可以使用所有dao的同一个会话,在初始化期间打开,在关闭时关闭。注意,Hibernate参考中提到了"每个操作会话"作为反模式:

"不要使用Session -per-operation反模式:不要在单个线程中为每个简单的数据库调用打开和关闭Session。"

在我看来,这在某种程度上与上面提到的方向相矛盾。我必须保持会话打开并重用它,不是吗?我认为,对于任何操作,只是在会话上打开会话,而不关闭它们,只意味着实现内存泄漏。在这里,使用应用程序作用域的会话池可能也不够,因为一个线程可以检查一个会话,而另一个线程可能访问绑定到该会话的延迟加载集合,这就是并发性问题。

在Spring框架中有解决方案,但是没有它,并且给定一个长时间运行的,基于jsf的,多线程和多用户的web应用程序:如何更好地管理它?

嗯,最简单的答案是"看情况而定"。

如果你的web应用有很高的流量,有大量的用户,我会为每个请求使用一个hibernate会话。

如果你有几个用户有长而复杂的会话,我会将一个hibernate会话映射到每个http会话。

对于第二种解决方案,您显然忘记了LazyLoading异常,但您也保持db会话打开,并且通常不是非常活跃。

对于第一个,理论上您更准备吸收高流量,但您将不得不使用会话。在使用对象之前,刷新以"重新连接"对象到数据库。

在某些应用程序中,我只是两者都做。绝大多数用户都有一个请求范围的db会话,他们使用的屏幕也相应地编码。对于高级用户,我使用会话范围db会话,通常使用特定的屏幕。

相关内容

  • 没有找到相关文章

最新更新