Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

The Javaworld Get started with Hibernate tutorial states:

An instance of Session is lightweight and is inexpensive to create and destroy. 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.

Because Tomcat processes HTTP requests in multiple threads, thread safety is very necessary in web application. 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

Let’s implement it this way in the depths of a JSF based web application:

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. (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. Note that the Hibernate Reference mentions "session per operation" as an antipattern:

"Do not use the session-per-operation antipattern: do not open and close a Session for every simple database call in a single thread."

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?

like image 547
Matthias Ronge Avatar asked Nov 10 '22 07:11

Matthias Ronge


1 Answers

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.

If you have few users with long, complex sessions, I would map one hibernate session to every http session.

With the second solution, you clearly forget the LazyLoading exception, but you also keep db sessions opened, and typically not very active.

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.

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.

like image 82
Ludovic Pénet Avatar answered Nov 15 '22 08:11

Ludovic Pénet