简体   繁体   English

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

[英]Hibernate session handling when using lazy loading in a JSF web application

The Javaworld Get started with Hibernate tutorial states: Javaworld 开始使用Hibernate教程

An instance of Session is lightweight and is inexpensive to create and destroy. Session一个实例是轻量级的,创建和销毁成本低廉。 This is important because your application will need to create and destroy sessions all the time, perhaps on every request. 这很重要,因为您的应用程序需要始终创建和销毁会话,可能是在每个请求上。 Hibernate sessions are not thread-safe and should by design be used by only one thread at a time. Hibernate会话不是线程安全的,并且一次只能由一个线程使用。

Because Tomcat processes HTTP requests in multiple threads, thread safety is very necessary in web application. 由于Tomcat在多个线程中处理HTTP请求,因此在Web应用程序中非常需要线程安全性。 Accordingly, I read in this answer : 因此,我在这个答案中读到:

The session should be a local variable of each method. 会话应该是每个方法的局部变量。 By doing this, your DAO would become stateless, and thus inherently thread-safe, without any need for synchronization 通过这样做,您的DAO将变为无状态,因此本质上是线程安全的,无需任何同步

Let's implement it this way in the depths of a JSF based web application: 让我们在基于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();
    }
}

When it comes to lazy loading you will surely get a LazyInitializationException when, minutes or hours after, some user interaction requires to access a lazy loaded collection on an object that is stored in the user session and was read from Hibernate with the above code, because the session used to load it was closed a long time ago. 当涉及到延迟加载时,你肯定会在几分钟或几小时之后得到一个LazyInitializationException,一些用户交互需要访问存储在用户会话中的对象的延迟加载集合,并且使用上面的代码从Hibernate读取,因为用于加载它的会话很久以前就关闭了。 (I don't consider refraining from lazy loading, which is proposed most often, as a solution here.) (我不认为在这里作为解决方案避免延迟加载,这是最常提出的。)

Continuing to read here , I also find: 继续在这里阅读,我也发现:

You could instead use one and the same session by all DAOs, opened sometime during intialization and closed at shutdown. 您可以使用所有DAO使用同一个会话,在初始化期间打开并在关闭时关闭。 Note that the Hibernate Reference mentions "session per operation" as an antipattern: 请注意, Hibernate Reference提到“每个操作的会话”作为反模式:

"Do not use the session-per-operation antipattern: do not open and close a Session for every simple database call in a single thread." “不要使用session-per-operation反模式:不要在单个线程中为每个简单的数据库调用打开和关闭Session。”

To my eyes, this somehow contradicts the directions mentioned above. 在我看来,这与上述方向有些矛盾。 I have to keep the session open and reuse it, or don't I? 必须保持会话开放并重用它,或者不是吗? I assume that just opening sessions over sessions for any operation and never closing them would just mean to implement a memory leak. 我假设只是在任何操作的会话上打开会话而从不关闭它们只是意味着实现内存泄漏。 Using an application scoped pool of sessions may not be enough here either, because one thread could check out one session while another thread might access a lazy loaded collection bound to just that session and there it is, the concurrency issue. 在这里使用应用程序范围的会话池可能还不够,因为一个线程可以检出一个会话,而另一个线程可能访问绑定到该会话的延迟加载的集合,并且就是并发问题。

There are solutions in the Spring framework , but without that and given a long-running, JSF-based, multi-threading and multi-user web application: How to preferably manage this? Spring框架中有解决方案 ,但没有它,并且给出了一个长期运行的,基于JSF的,多线程和多用户的Web应用程序:如何优先管理它?

Well, the simple answer is "it depends...". 嗯,简单的答案是“它取决于......”。

If your webapp has a high trafic, with an important number of user, I would use one hibernate session per request. 如果您的webapp具有高流量,并且有大量用户,我会在每个请求中使用一个休眠会话。

If you have few users with long, complex sessions, I would map one hibernate session to every http session. 如果您的用户很少有长而复杂的会话,我会将一个休眠会话映射到每个http会话。

With the second solution, you clearly forget the LazyLoading exception, but you also keep db sessions opened, and typically not very active. 使用第二个解决方案,您会清楚地忘记LazyLoading异常,但您也会保持数据库会话打开,并且通常不会非常活跃。

With the first one, you are theorically more prepared to absord high trafic, but you will have to use session.refresh to "reconnect" your objects to the database before using them. 对于第一个,你在理论上更准备去逃避高流量,但你必须使用session.refresh在使用它们之前将对象“重新连接”到数据库。

In some apps, I just do both. 在某些应用程序中,我只是两个都做。 The vast majority of user have a request scoped db session, and the screens they use are coded accordingly. 绝大多数用户都有一个请求作用域数据库会话,他们使用的屏幕也相应编码。 And I use session scoped db sessions for power users, typically using specific screens. 我为高级用户使用会话范围的数据库会话,通常使用特定的屏幕。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM