04: Identifying and fixing LazyInitializationException in Hibernate

LazyInitializationException is thrown when an object becomes detached, and if you try to access associated (i.e. proxied) object(s) of a detached object.

Q. What is a detached object in Hibernate?

When you close an individual Hibernate Session, the persistent objects you are working with are detached. This means the object is still in the application’s memory, but Hibernate is no longer responsible for tracking changes to that object. If your detached object has any associated objects, for example a “Book” object might have an associated proxied “Author” object. So, when you do something like

Hibernate needs to go database to initialize the proxy object. This is known as the “lazy” initialization of the “Author” object. Load it only when it is required. Now, if your Hibernate session is closed, then the database connection is closed and Hibernate cannot load the proxy object.

Hibernate Lazy InitializationException

Hibernate Lazy InitializationException

Q. What is a unit-of-work?

A session means a physical connection to a database. Hibernate session is a unit of work. You start a unit of work by “opening a session” and close the unit of work by closing a session. You also flush() a Session at the end of a unit of work to execute the SQL. The right approach to manage a “unit of work” is to define clear transaction boundaries in your application by beginning and committing transactions either declaratively or programmatically.

Session-per-request Vs long-conversations unit-of-work

The most common pattern in a multi-user client/server application is session-per-request. In this model, a request from the client is sent to the server, where the Hibernate persistence layer runs. A new Hibernate Session is opened, and all database operations are executed in this unit of work. On completion of the work, and once the response for the client has been prepared, the session is flushed or committed and the session is closed.

A very common approach is to use Spring with Hibernate, and Spring will take take care of the transaction management. Start a transaction when a server request has to be processed, and end the transaction before the response is sent to the client. Add Spring @Transactional annotation on the service layer making calls to the Hibernate repository or DAO layer. Spring provides a transaction abstraction layer over the Hibernate transaction API, and enables persistent operations to participate in global transactions. “org.springframework.orm.hibernate3.HibernateTransactionManager” for the local transactions (i.e. 1 datasource) and org.springframework.transaction.jta.JtaTransactionManager for the global JTA transactions.

There are business usecases that require a “conversational scope” with the user that are interleaved with multiple database accesses. This requires Long conversations

1) User retrieves data
2) The user modifies some objects and clicks save after 2 minutes.
3) The user makes more changes ….

You have to use several database transactions to implement this conversation. It is a bad idea to keep the transaction open for the whole conversation, even during the user think time (e.g. 2 minute before saving the loaded data). So, to deal with these types of long conversations Hibernate has features such as

1) Detached Objects: Allowing you to apply the session-per-request pattern where all the loaded instances will be “detached” during the user think time, and Hibernate allows you to reattach them to a new session. This pattern is known as session-per-request-with-detached-objects.

2) Extended (or Long) Session: where the Hibernate Session can be disconnected from the underlying JDBC connection after the database transaction has been committed and reconnected when a new client request occurs. This pattern is known as session-per-conversation and makes even reattachment unnecessary.

In both the above patterns, the Hibernate’s automatic Versioning can be used to detect and prevent possibilities of any concurrent modification issues due to the use think times. For example, users A and B might view the same data and user “A” might modify & save after “1 minute” of think time and user “B” might try to save after “2 minute” of think time not being aware of user “A’s” changes. The Hibernate versioning will indicate that the user “B’s” data is stale by throwing an exception where the user “B” has to redo the modification on the modified data.

Q. When is this exception thrown?

Step 1: User retrieves data

Step 2:The Hibernate session gets closed, as the user may take some time to modify the data or drill down into author details. You don’t want to keep the session open during the think time.

Step 3: The user drills down into the loaded “Book” object to view the “Author” details. The “Book” is a detached object.

Now the “LazyInitializationException” is thrown as the Hibeernate session is closed and cannot load the proxied “Author” data.

Q. How to fix this exception?

Approach 1: Eagerly fetch the Author without proxing

This approach is easy to setup, but if you have a complex object dependency graph, you will end up eagerly loading lots of objects into the heap, and causing performance issues.

Approach 2: Hibernate extended session

If you are using JPA with Hibernate, you ca use the @PersistenceContext(type = PersistenceContextType.EXTENDED). This allows you to access a lazy property anywhere (i.e. even if it is detached). PerssitenceContextType.EXTENDED means that you are in charge of managing your session, and Spring will not do it for you. PersistenceContextType.EXTENDED is useful in limited scenarios where a session-per-conversation is required.

You need to be very careful with this approach as it can cause “N+1” issues.

Approach 3: Use the join query

This is more like fetching eagerly on a as needed basis.

Approach 4: Load or get the entity again

Load the associated entity within the same session.


Java Interview FAQs

800+ Java Interview Q&As

Top