How to fetch FetchType.LAZY associations with JPA and Hibernate in a Spring Controller
To manage Hibernate sessions for LAZY associations, use the decorator @Transactional
. Have a look at this code snippet:
With this pattern, LAZY associations are initialized within a Hibernate session that's up and running - thus, you can bid a not-so-tearful adieu to the feared LazyInitializationException. All you need to do is call Hibernate.initialize()
on each LAZY association you want to be loaded.
Making sense of FetchType.LAZY
Efficiently handling LAZY loading in a Spring Controller requires a number of tactics and considerations:
The magic of fetch joins
Using Fetch joins in JPQL help you to load associated entities in one go instead of loading them separately. This can be accomplished directly in a repository method:
A service layer, your session guardian
An intermediate Service layer can work like a buffer between your controller and your repositories. It makes sure the session is up and running while operations on LAZY collections are carried out.
Use @EntityGraph for a custom touch
You can customize fetching strategies through @EntityGraph
. This allows for the specification of a load graph at the method level in your repository:
Single fetch join VS multiple queries
It's critical to think about the trade-off between multiple queries and using fetch joins. Fetch joins might decrease the number of queries but, beware, they also might lead to fetching more data than actually required.
@Transactional: non-negotiable!
Ensure that your fetching protocol always operates within a @Transactional
framework so that the session remains open and the dreaded LazyInitializationException does not pop up.
Get those proxies working
Maximize the usage capabilities of Spring Data JPA's findById
or custom methods for fetching LAZY associations in a proper manner. Also, make sure to use proxies to tie parent entities when persisting child entities to bypass any lazy loading-related complications.
Performance matters
Concern yourself with loading LAZY data only as required in order to keep off unnecessary overhead. Eagerly loading all relations, irrespective of actual need, can be detrimental to performance.
A deep dive into FetchType.LAZY
Life-cycle management of session
In order for LAZY initialization to succeed, a Hibernate session needs to be up and running. The OpenEntityManagerInViewFilter
can help keep the session open for the whole duration of a web request, thereby helping you evade the LazyInitializationException.
Initiation of lazy loading
Either a service method or a direct access to the lazy collection can kick-start lazy loading. If you call .size()
on the collection or implement any other method that needs to gain access to the collection data, initialization is triggered.
Eager fetching: use with caution
Do exercise caution while setting fetching to FetchType.EAGER
or using eager fetching repository methods indiscriminately, as doing so could lead to performance degradation and a ramp-up in memory consumption.
Repository helper utilities
Do give a thought to creating a utility such as a RepositoryHelper
or utilizing JpaUtils
to separate the often complicated entity initialization logic from your business service layer, thereby keeping your codebase clean and maintainable.
Avoid LazyInitializationException
Implement the following practices and strategies to silently load lazy associations, or gracefully tackle exceptions in scenarios where lazy data is being accessed out of transaction scope:
- Service Layer - Ensures transactions are open during lazy loading.
- Entity Graphs - Define fetch plans for selective eager loading.
- Spring Repositories - Manage how and when to fetch associations with custom methods.
Was this article helpful?