eBook – Guide Spring Cloud – NPI EA (cat=Spring Cloud)
announcement - icon

Let's get started with a Microservice Architecture with Spring Cloud:

>> Join Pro and download the eBook

eBook – Mockito – NPI EA (tag = Mockito)
announcement - icon

Mocking is an essential part of unit testing, and the Mockito library makes it easy to write clean and intuitive unit tests for your Java code.

Get started with mocking and improve your application tests using our Mockito guide:

Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Reactive – NPI EA (cat=Reactive)
announcement - icon

Spring 5 added support for reactive programming with the Spring WebFlux module, which has been improved upon ever since. Get started with the Reactor project basics and reactive programming in Spring Boot:

>> Join Pro and download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Jackson – NPI EA (cat=Jackson)
announcement - icon

Do JSON right with Jackson

Download the E-book

eBook – HTTP Client – NPI EA (cat=Http Client-Side)
announcement - icon

Get the most out of the Apache HTTP Client

Download the E-book

eBook – Maven – NPI EA (cat = Maven)
announcement - icon

Get Started with Apache Maven:

Download the E-book

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

eBook – RwS – NPI EA (cat=Spring MVC)
announcement - icon

Building a REST API with Spring?

Download the E-book

Course – LS – NPI EA (cat=Jackson)
announcement - icon

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

>> LEARN SPRING
Course – RWSB – NPI EA (cat=REST)
announcement - icon

Explore Spring Boot 3 and Spring 6 in-depth through building a full REST API with the framework:

>> The New “REST With Spring Boot”

Course – LSS – NPI EA (cat=Spring Security)
announcement - icon

Yes, Spring Security can be complex, from the more advanced functionality within the Core to the deep OAuth support in the framework.

I built the security material as two full courses - Core and OAuth, to get practical with these more complex scenarios. We explore when and how to use each feature and code through it on the backing project.

You can explore the course here:

>> Learn Spring Security

Course – LSD – NPI EA (tag=Spring Data JPA)
announcement - icon

Spring Data JPA is a great way to handle the complexity of JPA with the powerful simplicity of Spring Boot.

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

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (cat=Spring Boot)
announcement - icon

Refactor Java code safely — and automatically — with OpenRewrite.

Refactoring big codebases by hand is slow, risky, and easy to put off. That’s where OpenRewrite comes in. The open-source framework for large-scale, automated code transformations helps teams modernize safely and consistently.

Each month, the creators and maintainers of OpenRewrite at Moderne run live, hands-on training sessions — one for newcomers and one for experienced users. You’ll see how recipes work, how to apply them across projects, and how to modernize code with confidence.

Join the next session, bring your questions, and learn how to automate the kind of work that usually eats your sprint time.

Course – LJB – NPI EA (cat = Core Java)
announcement - icon

Code your way through and build up a solid, practical foundation of Java:

>> Learn Java Basics

1. Overview

Managing the SQL statements from our applications is one of the most important things we need to take care of because of its huge impact on performance. When working with relations between objects, there are two main design patterns for fetching. The first one is the lazy approach, while the other one is the eager approach.

In this article, we’ll take an overview of both of them. In addition, we’ll discuss the @LazyCollection annotation in Hibernate.

2. Lazy Fetching

We use lazy fetching when we want to postpone the data initialization until we need it. Let’s look at an example to better understand the idea.

Suppose we have a company that has multiple branches in the city. Every branch has its own employees. From the database perspective, it means we have a one-to-many relation between the branch and its employees.

In the lazy fetching approach, we won’t fetch the employees once we fetch the branch object. We only fetch the data of the branch object, and we postpone loading the list of employees until we call the getEmployees() method. At that point, another database query will be executed to get the employees.

The benefit of this approach is that we reduce the amount of data loaded initially. The reason is that we might not need the employees of the branch, and there’s no point in loading them since we aren’t planning to use them right away.

3. Eager Fetching

We use eager fetching when the data needs to be loaded instantly. Let’s take the same example of the company, branches, and the employees to explain this idea as well. Once we load some branch object from the database, we’ll immediately load the list of its employees as well using the same database query.

The main concern when using the eager fetching is that we load a huge amount of data that might not be needed. Hence, we should only use it when we’re sure that the eagerly fetched data will always be used once we load its object.

4. The @LazyCollection Annotation

We use the @LazyCollection annotation when we need to take care of the performance in our application. Starting from Hibernate 3.0, @LazyCollection is enabled by default. The main idea of using the @LazyCollection is to control whether the fetching of data should be using the lazy approach or the eager one.

When using @LazyCollection, we have three configuration options for the LazyCollectionOption setting: TRUE, FALSE, and EXTRA. Let’s discuss each of them independently.

4.1. Using LazyCollectionOption.TRUE

This option enables the lazy fetching approach for the specified field and is the default starting from Hibernate version 3.0. Therefore, we don’t need to explicitly set this option. However, to explain the idea in a better way, we’ll take an example where we set this option.

In this example, we have a Branch entity that consists of an id, name, and a @OneToMany relation to the Employee entity. We can notice that we set the @LazyCollection option explicitly to true in this example:

@Entity
public class Branch {

    @Id
    private Long id;

    private String name;

    @OneToMany(mappedBy = "branch")
    @LazyCollection(LazyCollectionOption.TRUE)
    private List<Employee> employees;
    
    // getters and setters
}

Now, let’s take a look at the Employee entity that consists of an id, name, address, as well as a @ManyToOne relation with the Branch entity:

@Entity
public class Employee {

    @Id
    private Long id;

    private String name;

    private String address;
    
    @ManyToOne
    @JoinColumn(name = "BRANCH_ID") 
    private Branch branch; 

    // getters and setters 
}

In the above example, when we get a branch object, we won’t load the list of employees immediately. Instead, this operation will be postponed until we call the getEmployees() method.

4.2. Using LazyCollectionOption.FALSE

When we set this option to FALSE, we enable the eager fetching approach. In this case, we need to explicitly specify this option because we’ll be overriding Hibernate’s default value. Let’s look at another example.

In this case, we have the Branch entity, which contains id, name, and a @OneToMany relation with the Employee entity. Note that we set the option of @LazyCollection to FALSE:

@Entity
public class Branch {

    @Id
    private Long id;

    private String name;

    @OneToMany(mappedBy = "branch")
    @LazyCollection(LazyCollectionOption.FALSE)
    private List<Employee> employees;
    
    // getters and setters
}

In the above example, when we get a branch object, we’ll load the branch with the list of employees instantly.

4.3. Using LazyCollectionOption.EXTRA

Sometimes, we’re only concerned with the properties of the collection, and we don’t need the objects inside it right away.

For example, going back to the Branch and the Employees example, we could just need the number of employees in the branch while not caring about the actual employees’ entities. In this case, we consider using the EXTRA option. Let’s update our example to handle this case.

Similar to the case before, the Branch entity has an id, name, and an @OneToMany relation with the Employee entity. However, we set the option for @LazyCollection to be EXTRA:

@Entity
public class Branch {

    @Id
    private Long id;

    private String name;

    @OneToMany(mappedBy = "branch")
    @LazyCollection(LazyCollectionOption.EXTRA)
    @OrderColumn(name = "order_id")
    private List<Employee> employees;

    // getters and setters
    
    public Branch addEmployee(Employee employee) {
        employees.add(employee);
        employee.setBranch(this);
        return this;
    }
}

We notice that we used the @OrderColumn annotation in this case. The reason is that the EXTRA option is taken into consideration only for indexed list collections. That’s means if we didn’t annotate the field with @OrderColumn, the EXTRA option will give us the same behavior as lazy and the collection will be fetched when accessed for the first time.

In addition, we define the addEmployee() method as well, because we need the Branch and the Employee to be synchronized from both sides. If we add a new Employee and set a branch for him, we need the list of employees inside the Branch entity to be updated as well.

Now, when persisting one Branch entity that has three associated employees, we’ll need to write the code as:

entityManager.persist(
  new Branch().setId(1L).setName("Branch-1")

    .addEmployee(
      new Employee()
        .setId(1L)
        .setName("Employee-1")
        .setAddress("Employee-1 address"))
  
    .addEmployee(
      new Employee()
        .setId(2L)
        .setName("Employee-2")
        .setAddress("Employee-2 address"))
  
    .addEmployee(
      new Employee()
        .setId(3L)
        .setName("Employee-3")
        .setAddress("Employee-3 address"))
);

If we take a look at the executed queries, we’ll notice that Hibernate will insert a new Branch for Branch-1 first. Then it will insert Employee-1, Employee-2, then Employee-3.

We can see that this is a natural behavior. However, the bad behavior in the EXTRA option is that after flushing the above queries, it’ll execute three additional ones – one for every Employee we add:

UPDATE EMPLOYEES
SET
    order_id = 0
WHERE
    id = 1
     
UPDATE EMPLOYEES
SET
    order_id = 1
WHERE
    id = 2
 
UPDATE EMPLOYEES
SET
    order_id = 2
WHERE
    id = 3

The UPDATE statements are executed to set the List entry index. This is an example of what’s known as the N+1 query issue, which means that we execute N additional SQL statements to update the same data we created.

As we noticed from our example, we might have the N+1 query issue when using the EXTRA option.

On the other hand, the advantage of using this option is when we need to get the size of the list of employees for every branch:

int employeesCount = branch.getEmployees().size();

When we call this statement, it’ll only execute this SQL statement:

SELECT
    COUNT(ID)
FROM
    EMPLOYEES
WHERE
    BRANCH_ID = :ID

As we can see, we didn’t need to store the employees’ list in memory to get its size. Nevertheless, we advise avoiding the EXTRA option because it’ll execute additional queries.

It’s also worth noting here that it’s possible to encounter the N+1 query issue with other data access technologies, as it isn’t only restricted to JPA and Hibernate.

5. Conclusion

In this article, we discussed the different approaches to fetching an object’s properties from the database using Hibernate.

First, we discussed lazy fetching with an example. Then, we updated the example to use eager fetching and discussed the differences.

Finally, we showed an extra approach to fetching the data and explained its advantages and disadvantages.

The code backing this article is available on GitHub. Once you're logged in as a Baeldung Pro Member, start learning and coding on the project.
Baeldung Pro – NPI EA (cat = Baeldung)
announcement - icon

Baeldung Pro comes with both absolutely No-Ads as well as finally with Dark Mode, for a clean learning experience:

>> Explore a clean Baeldung

Once the early-adopter seats are all used, the price will go up and stay at $33/year.

eBook – HTTP Client – NPI EA (cat=HTTP Client-Side)
announcement - icon

The Apache HTTP Client is a very robust library, suitable for both simple and advanced use cases when testing HTTP endpoints. Check out our guide covering basic request and response handling, as well as security, cookies, timeouts, and more:

>> Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

Course – LS – NPI EA (cat=REST)

announcement - icon

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

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (tag=Refactoring)
announcement - icon

Modern Java teams move fast — but codebases don’t always keep up. Frameworks change, dependencies drift, and tech debt builds until it starts to drag on delivery. OpenRewrite was built to fix that: an open-source refactoring engine that automates repetitive code changes while keeping developer intent intact.

The monthly training series, led by the creators and maintainers of OpenRewrite at Moderne, walks through real-world migrations and modernization patterns. Whether you’re new to recipes or ready to write your own, you’ll learn practical ways to refactor safely and at scale.

If you’ve ever wished refactoring felt as natural — and as fast — as writing code, this is a good place to start.

Course – LSD – NPI (cat=JPA)
announcement - icon

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

>> CHECK OUT THE COURSE

eBook Jackson – NPI EA – 3 (cat = Jackson)