Initializing the whole entity and its associated entities/collections is never a good idea. So hibernate allows us to lazy load the data when needed but within an active Session. But what if we need to access data at some other place outside the transaction boundary and hibernate session will be closed by then.
1. Default Lazy Initialization
Hibernate does not support lazy initialization for detached objects. Typically, we load an entity using Hibernate Session and work through it, and finally, we close the session. After closing the session, the entity becomes a detached entity, so it cannot make further calls to the database until again associated with a new Session.
LazyInitializationException will be thrown by Hibernate if an uninitialized collection or proxy is accessed outside of the scope of the Session, i.e., when the entity owning the collection or having the reference to the proxy is in the detached state.
Well, we have got a few approaches if we are not using lazy initialization. Let’s list them down first:
- Use EAGER initialization: This is an easy approach but most dangerous if not used carefully. It has the potential to bring down your whole application in runtime if there are cyclic dependencies between entities. My suggestion is to never use it until we are absolutely sure of it.
- Do not close the Session until the Job is complete: This is another easy approach. But it forces the database connection to keep open for a long time. It can reduce the application performance considerably.
- Fetch required data in DAO before the Session is closed or open a new session: This seems the most appropriate approach in most cases. When we know what data we will need next, just load it before closing the session. Or open a new session when we really need that data.
2. Using enable_lazy_load_no_trans Property
We can use
hibernate.enable_lazy_load_no_trans or the ENABLE_LAZY_LOAD_NO_TRANS configuration, if we don’t want to make any code change and bypass all lazy-loading-related issues that happen during proxy access outside an active Session.
- This setting will load proxy entity and collection in detached entities as well.
- It makes hibernate to fetch a lazy entity inside a temporarily opened Session and a separate transaction.
But use this session with caution. We will not be able to port our project to other JPA providers if needed. We also can have the N+1 effect. Also every time we will get the latest version of the data from the database that may not be desired in some cases.
3. Using Hibernate.initialize()
Sometimes a proxy or collection needs to be initialized before closing the Session. One way is to force initialization by calling
entity.getXXX().size(), for example. However, this can be confusing to readers of the code and it is not convenient for generic code.
The static methods
Hibernate.isInitialized() provide the application with a convenient way of working with lazily initialized collections or proxies.
Hibernate.initialize(entity.getXXX()) will force the initialization of a proxy entity or collection entity.getXXX() as long as the Session is still open.
e.g. If we have two entity types
Department, then we can easily initialize lazy load enabled collection of students like below:
Department dept = (Department) session.get(Department.class, deptId); //*****Initialize student collection******* Hibernate.initialize(dept.getStudents()); session.close();
The above code will, immediately, load the list of students. Now we are safe to close the session and we will be able to get data as and when required. It’s a much cleaner way of pre-initializing lazy load-enabled proxy or collection objects.
In this short hibernate tutorial, we learned to initialize a lazy loading proxy entity or collection inside or outside the active Session boundary. I will suggest reading them in-depth before using them, as they have a wider impact than we estimate.
Happy Learning !!