1. Overview

When working with an ORM, data fetching/loading can be classified into two types: eager and lazy.

In this quick tutorial, we are going to point out differences and show how we can use these in Hibernate.

2. Maven Dependencies

In order to use Hibernate, let’s first define the main dependency in our pom.xml:


The latest version of Hibernate can be found here.

3. Eager and Lazy Loading

The first thing that we should discuss here is what lazy loading and eager loading are:

  • Eager Loading is a design pattern in which data initialization occurs on the spot.
  • Lazy Loading is a design pattern that we use to defer initialization of an object as long as it’s possible.

Let’s see how this works.

First, we’ll look at the UserLazy class:

@Table(name = "USER")
public class UserLazy implements Serializable {

    @Column(name = "USER_ID")
    private Long userId;

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "user")
    private Set<OrderDetail> orderDetail = new HashSet();

    // standard setters and getters
    // also override equals and hashcode


Next, we’ll see the OrderDetail class:

@Table (name = "USER_ORDER")
public class OrderDetail implements Serializable {
    private Long orderId;
    @ManyToOne(fetch = FetchType.LAZY)
    private UserLazy user;

    // standard setters and getters
    // also override equals and hashcode


One User can have multiple OrderDetails. In eager loading strategy, if we load the User data, it will also load up all orders associated with it and will store it in a memory.

But when we enable lazy loading, if we pull up a UserLazy, OrderDetail data won’t be initialized and loaded into a memory until we make an explicit call to it.

In the next section, we’ll see how we implement the example in Hibernate.

4. Loading Configuration

Let’s look at how to configure fetching strategies in Hibernate.

We can enable Lazy Loading by using this annotation parameter:

fetch = FetchType.LAZY

For Eager Fetching, we use this parameter:

fetch = FetchType.EAGER

To set up Eager Loading, we have used UserLazy‘s twin class called UserEager.

In the next section, we will look at the differences between the two types of fetching.

5. Differences

As we mentioned, the main difference between the two types of fetching is the moment when data gets loaded into a memory.

Let’s have a look:

List<UserLazy> users = sessionLazy.createQuery("From UserLazy").list();
UserLazy userLazyLoaded = users.get(3);
return (userLazyLoaded.getOrderDetail());

With the lazy initialization approach, orderDetailSet will get initialized only when we explicitly call it, using a getter or some other method:

UserLazy userLazyLoaded = users.get(3);

But with an eager approach in UserEager, it will be initialized immediately in the first line:

List<UserEager> user = sessionEager.createQuery("From UserEager").list();

For lazy loading, we use a proxy object and fire a separate SQL query to load the orderDetailSet.

The idea of disabling proxies or lazy loading is considered a bad practice in Hibernate. It can result in fetching and storing a lot of data, irrespective of the need for it.

We can use the following method to test the functionality:


Now let’s have a look at the queries generated in either case:

<property name="show_sql">true</property>

The above setting in the fetching.hbm.xml shows the generated SQL queries. If we look at a console output, we can see generated queries.

For Lazy Loading, here’s the query generated to load the User data:

select user0_.USER_ID as USER_ID1_0_,  ... from USER user0_

However, in eager loading, we saw a join made with USER_ORDER:

select orderdetai0_.USER_ID as USER_ID4_0_0_, orderdetai0_.ORDER_ID as ORDER_ID1_1_0_, orderdetai0_ ...
  from USER_ORDER orderdetai0_ where orderdetai0_.USER_ID=?

The above query is generated for all Users, which results in much more memory use than in the other approach.

6. Advantages and Disadvantages

6.1. Lazy Loading


  • Much smaller initial load time than in the other approach
  • Less memory consumption than in the other approach


  • Delayed initialization might impact performance during unwanted moments.
  • In some cases we need to handle lazily initialized objects with special care, or we might end up with an exception.

6.2. Eager Loading


  • No delayed initialization-related performance impacts


  • Long initial loading time
  • Loading too much unnecessary data might impact performance

7. JPA Default FetchType

As we’ve seen earlier, the fetch attribute can be either FetchType.LAZY or FetchType.EAGER. By default, @OneToMany and @ManyToMany associations use the FetchType.LAZY strategy while the @OneToOne and @ManyToOne use the FetchType.EAGER strategy instead.

8. Lazy Loading in Hibernate

Hibernate applies lazy loading approach on entities and associations by providing a proxy implementation of classes.

Hibernate intercepts calls to an entity by substituting it with a proxy derived from an entity’s class. In our example, missing requested information will be loaded from a database before control is ceded to the User class implementation.

We should also note that when the association is represented as a collection class (in the above examples, it is represented as Set<OrderDetail> orderDetailSet), a wrapper is created and substituted for an original collection.

To know more about proxy design pattern, refer here.

9. Conclusion

In this article, we showed examples of the two main types of fetching used in Hibernate.

For advanced expertise, check the official website of Hibernate.

To get the code discussed in this article, please have a look at this repository.

Course – LS (cat=Spring)

Get started with Spring and Spring Boot, through the Learn Spring course:

Course – LSD (cat=Persistence)

Get started with Spring Data JPA through the reference Learn Spring Data JPA course:

res – Persistence (eBook) (cat=Persistence)
Comments are open for 30 days after publishing a post. For any issues past this date, use the Contact form on the site.