In Hibernate (and Spring Data JPA), lazy loading is the recommended strategy for controlling when associated entities are fetched. This improves performance by avoiding unnecessary database queries when associated data is not needed.
This guide explains how to ensure Hibernate does not automatically load associated entities when the main entity is loaded, along with best practices and practical examples for enforcing lazy loading in your Spring Boot applications.
⚙️ Step-by-Step Guide to Lazy Loading in Hibernate
✅ 1. Use FetchType.LAZY
in Relationships
Hibernate uses two fetching strategies: EAGER
and LAZY
. Setting associations to lazy ensures they are only loaded when explicitly accessed.
🔹 For @OneToMany
and @ManyToMany
(Default is LAZY
, but good to be explicit.)
java
@Entity
public class MainEntity {
@Id
private Long id;
@OneToMany(fetch = FetchType.LAZY, mappedBy = "mainEntity")
private Set<AssociatedEntity> associatedEntities = new HashSet<>();
}
🔹 For @ManyToOne
and @OneToOne
(Default is EAGER
— must override to LAZY
.)
java
@Entity
public class MainEntity {
@Id
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "associated_id")
private AssociatedEntity associatedEntity;
}
✅ 2. Enable Bytecode Enhancement for Advanced Lazy Loading
To lazily load @OneToOne
and even basic fields, you need bytecode enhancement.
🔸 Maven Configuration
xml
<plugin>
<groupId>org.hibernate.orm.tooling</groupId>
<artifactId>hibernate-enhance-maven-plugin</artifactId>
<version>${hibernate.version}</version>
<executions>
<execution>
<goals>
<goal>enhance</goal>
</goals>
<configuration>
<enableLazyInitialization>true</enableLazyInitialization>
</configuration>
</execution>
</executions>
</plugin>
🔸 Gradle Configuration
groovy
plugins {
id 'org.hibernate.orm' version '6.0.0.Final'
}
hibernate {
enhance {
enableLazyInitialization = true
}
}
✅ 3. Allow Hibernate to Create Proxies
Hibernate relies on proxy objects for lazy loading. To allow proxy creation:
- ✅ Entity classes must not be
final
- ✅ Must have a non-final no-arg constructor
Without these, Hibernate cannot lazily load associated entities.
✅ 4. Avoid JOIN FETCH
in JPQL or HQL
Using JOIN FETCH
forces eager loading and overrides FetchType.LAZY
.
java
// ❌ Eagerly loads associated entities
String query = "SELECT m FROM MainEntity m JOIN FETCH m.associatedEntities";
// ✅ Use this to preserve lazy loading
String query = "SELECT m FROM MainEntity m";
📌 Summary Table
StrategyPurposefetch = FetchType.LAZY
Prevents automatic loading of associationsBytecode enhancementEnables field-level and @OneToOne
lazyAvoiding JOIN FETCH
in JPQLPrevents eager loading via queriesHibernate proxy-friendly setupSupports lazy loading via proxy mechanism
🧠 Bonus Tip: Handle LazyInitializationException
Lazy loading works only within an active Hibernate session. Accessing a lazily loaded association outside this session throws a LazyInitializationException
.
✅ To avoid this:
- Annotate your service methods with
@Transactional
- Or explicitly load the needed associations before returning the object
With these strategies, you gain fine-grained control over entity loading, significantly improving performance and ensuring scalable data handling in Spring and Hibernate-based applications.