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会话,通常使用特定的屏幕。