10k

How to solve "org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: xxx, no session or session was closed"

Behaviour

I was working on a new asynchronous message, and queried an object from database. While using it, I got:

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: xxx, no session or session was closed

Analysis

At first I mainly focused on the "lazy". So I check the why this happened. Then it comes to the lazy load versus eager load.

While in this situation, the lazy load means an object has a reference on it, there is a one-to-many relationship. When hibernate is fetching the object, lazy load will not fetch all the stuff and only query them when they are used.

In such case, I check on the stackOverflow, where there is a suggestion that we could use eagerly fetch. I checked our code base and find someone had implemented such method: getObejctEagerlyById(), so I used it and the issue was resolved.

However, there is potential performance issue, and indeed, there is no need for us to query all the other objects.


At this point, my workmate guess if it'd due to the session issue. So I checked more resources. This time the point lies in the "no session or session was closed". (It's reasonable, now looking back, "org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: xxx, no session or session was closed", "no session or session was closed" is the reason in the error message and we should start from it at the beginning.)

Root cause

The root cause is that here we start new session by hibernate and close it immediately after query. Thus, the joined SQL doesn't have a context. For example, if you query object A, whose attributes includes object B. If you are using an eager fetch, you will fetch all B's of A when querying A; and if you use lazy fetch, you will only get the SQL before left join and commit immediately after execution.

Solution

  1. Use eager fetch(no recommended in this issue)

  2. Use OpenSessionInViewFilter, it will handover the session management to servlet filter, it will create a new session for each new request and close it after response.

    LazyInitializationException often occur in view layer. If you use Spring framework, you can use OpenSessionInViewFilter. However, I do not suggest you to do so. It may leads to performance issue if not use correctly.

  3. @Transactional in controller layer and extend the session lifecycle.

Reference

  1. How to solve the “failed to lazily initialize a collection of role” Hibernate exception
  2. org.hibernate.LazyInitializationException: failed to lazily initialize
  3. 解决Hibernate:could not initialize proxy - no Session
Thoughts? Leave a comment