Java Persistence API
FetchType LAZY
FetchType EAGER
Hibernate
Database Optimization

Difference between FetchType LAZY and EAGER in Java Persistence API?

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

In Java Persistence API (JPA), entity relationships are a core concept, and how these relationships are fetched—either eagerly or lazily—significantly impacts application performance and behavior. FetchType.LAZY and FetchType.EAGER are the two primary fetching strategies in JPA, and choosing the right one is crucial for efficient data access.

FetchType.EAGER

With FetchType.EAGER, JPA loads the associated entities as soon as the parent entity is loaded. This is the simplest form of fetching as it doesn't require any additional configuration or thought once set. It eliminates the need for the application to explicitly fetch parts of the graph later.

Example: Consider an Order entity with multiple Product entities.

java
1@Entity
2public class Order {
3    @Id
4    private Long id;
5
6    @OneToMany(fetch = FetchType.EAGER)
7    private Set<Product> products;
8}

Here, whenever an Order is fetched from the database, all associated Products are also automatically fetched, regardless of whether they are used or not.

FetchType.LAZY

FetchType.LAZY, on the other hand, means that the associated entities are loaded only on demand. This can lead to improved performance, especially if the associated entities are rarely accessed. Lazy loading uses proxy objects or collections that fetch the actual entities when accessed for the first time.

Example:

java
1@Entity
2public class Order {
3    @Id
4    private Long id;
5
6    @OneToMany(fetch = FetchType.LAZY)
7    private Set<Product> products;
8}

In this example, Product entities are not fetched with the Order. They are fetched only when the application accesses the products collection.

Key Differences

The core difference between these two approaches lies in when the associated data is loaded from the database. Eager fetching loads all data upfront, which can be beneficial when you know that you will use the data and it saves additional database calls later. However, it can lead to significant performance drawbacks if not used carefully, such as increased memory usage and slower query performance due to loading unnecessary data.

Lazy loading, while more efficient in terms of resource use, can lead to the infamous "N+1 selects problem." This problem occurs when the application needs to access each associated entity individually, thus creating a new database call for each access.

Considerations and Best Practices

  1. Use FetchType.LAZY by default: Start with lazy loading and switch to eager only if profiling dictates. It generally leads to better overall performance.
  2. Profile your application: Always measure the impact of fetching strategies on your application’s performance.
  3. Beware of the context: In some contexts, such as within transaction-bound contexts or read-only operations, lazy loading can be less efficient due to repeated opening and closing of session/transaction.
  4. Utilize fetching strategies: Consider utilizing batch fetching, fetch joins, or sub-selects to optimize lazy loading.

Summary Table

AttributeFetchType.LAZYFetchType.EAGER
Loading TimeOn AccessOn Initial Loading
Default ScenarioRecommended in most scenariosShould be used cautiously
Memory and Resource UtilizationGenerally lowerHigher, as all related data is loaded
SuitabilityBest for data that is not always neededGood when related data is always needed
Risk of N+1 ProblemHigher (but manageable with strategies)None

In conclusion, understanding the trade-offs between eager and lazy fetching in JPA is critical for developing high-performing Java applications. While lazy loading can be more complex to handle due to issues like the "N+1 selects problem," it often results in more scalable and efficient applications when used correctly. Conversely, eager fetching is straightforward but can lead to unnecessary data retrieval and increased memory usage. Designing your application with the appropriate fetching strategy in mind will lead to a more balanced and performant application.


Related reading
Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design