AdBlock Detected

It looks like you're using an ad-blocker!

Our team work realy hard to produce quality content on this website and we noticed you have ad-blocking enabled. Advertisements and advertising enable us to continue working and provide high-quality content.

FetchMode in Hibernate

In this article using FetchMode in Hibernate with Spring Data, we will explore the different ways to retrieve data using annotations.

In a previous article, we learned that using Join Fetch allows us to fetch data from the database in a single query.

Types of FetchMode in Hibernate

There are three different types of FetchMode, defined as an enum in the code:

public enum FetchMode {
  SELECT,
  JOIN,
  SUBSELECT;

  private FetchMode() {
  }
}
  • FetchMode of type SELECT: With SELECT mode, Hibernate behaves in a lazy manner to fetch child collections.
  • Type JOIN: With JOIN FetchMode, collections are fetched in a single query.
  • FetchMode of type SUBSELECT: When using SUBSELECT mode, separate queries are executed for the parent entity and the child collection.

Now that we have seen the three types of FetchMode in Hibernate, let’s dive into an example.

Example of using FetchMode in Hibernate with Spring Data

For our example, we will use two entities: Department and Employee, where Department has a one-to-many relationship with Employee.

Department Entity

@Getter
@Setter
@Entity
public class Department {

  @Id
  @Column(name = "DEPARTMENT_ID")
  @GeneratedValue(strategy = GenerationType.AUTO)
  private Integer departmentId;

  private String name;

  @OneToMany
  @Fetch(FetchMode.JOIN)
  private List<Employee> employees;

}

In the Department entity, we define different FetchModes to perform tests.

Employee Entity

@Getter
@Setter
@Entity
public class Employee {

  @Id
  @SequenceGenerator(name = "emp_seq", sequenceName = "seq_employee")
  @GeneratedValue(generator = "emp_seq")
  @Column(name = "EMPLOYEE_ID")
  private Integer id;

  private String name;

  private String surname;

  @ManyToOne
  @JoinColumn(name = "department_id")
  private Department department;

}

Based on the configured FetchMode, we will obtain employees with one query or N+1 queries, etc.

Using FetchMode SELECT

When using FetchMode.SELECT in Hibernate, child collections are lazily fetched from the database. In other words, one query is executed for the parent entity, and additional queries are executed for each child entity.

For example, if we configure the Department entity as follows:

@Getter
@Setter
@Entity
public class Department {

  @Id
  @GeneratedValue(generator = "uuid")
  @GenericGenerator(name = "uuid", strategy = "uuid2")
  private String id;

  private String name;

  @OneToMany
  @Fetch(value = FetchMode.SELECT)
  private Set<Employee> employees = new HashSet<>();

}

And run the following test:

  @Test
  @Transactional
  public void withoutJoinFetch() {
  Department department = departmentRepository.findById(1).orElseThrow();

  log.info("Employees -> {} ", department.getEmployees());

  }

When we execute the test and have only one Employee, the result will be as follows:

Hibernate: 
    select
        d1_0.id,
        d1_0.name 
    from
        department d1_0
Hibernate: 
    select
        e1_0.department_id,
        e1_0.id,
        e1_0.name,
        e1_0.surname 
    from
        employee e1_0 
    where
        e1_0.department_id=?

As a result, we performed one query for the Department entity and N queries depending on the number of Employees (in this case, 1).

We can use the @Batch annotation to fetch collections in batches, for example:

  @OneToMany
  @Fetch(value = FetchMode.SELECT)
  @Batch(size=5)
  private Set<Employee> employees = new HashSet<>();

FetchMode Join in Hibernate

By using FetchMode.JOIN in Hibernate, data from the database is retrieved in a single query.

For example, if we modify the Department entity as follows:

@Getter
@Setter
@Entity
public class Department {

  @Id
  @GeneratedValue(generator = "uuid")
  @GenericGenerator(name = "uuid", strategy = "uuid2")
  private String id;

  private String name;

  @OneToMany
  @Fetch(value = FetchMode.JOIN)
  private Set<Employee> employees = new HashSet<>();

}

When we execute the following test:

  @Test
  @Transactional
  public void withoutJoinFetch() {
  Department department = departmentRepository.findById(1).orElseThrow();

  log.info("Employees -> {} ", department.getEmployees());

  }

We can see in the results that there is a single query, meaning a join between tables to obtain all the results without making extra queries for employees.

Hibernate: 
    select
        d1_0.department_id,
        e1_0.department_department_id,
        e1_1.employee_id,
        d2_0.department_id,
        d2_0.name,
        e1_1.name,
        e1_1.surname,
        d1_0.name 
    from
        department d1_0 
    left join
        (department_employees e1_0 
    join
        employee e1_1 
            on e1_1.employee_id=e1_0.employees_employee_id) 
                on d1_0.department_id=e1_0.department_department_id 
        left join
            department d2_0 
                on d2_0.department_id=e1_1.department_id 
        where
            d1_0.department_id=?

With this approach, we can see that a join is performed to obtain all the results.

If we use CascadeType.ALL in our relationship, it will not function as a join and will execute multiple queries.

Using FetchMode.SUBSELECT in Hibernate

When using the SUBSELECT mode in Hibernate for a OneToMany relationship, two queries are executed in total, one to retrieve the parent (Department) and another to retrieve the collection (Employees).

@Getter
@Setter
@Entity
public class Department {

  @Id
  @GeneratedValue(generator = "uuid")
  @GenericGenerator(name = "uuid", strategy = "uuid2")
  private String id;

  private String name;

  @OneToMany
  @Fetch(value = FetchMode.SUBSELECT)
  private Set<Employee> employees = new HashSet<>();

}

If we execute our test:

  @Test
  @Transactional
  public void withoutJoinFetch() {
  Department department = departmentRepository.findById(1).orElseThrow();

  log.info("Employees -> {} ", department.getEmployees());

  }

We can see that there are two queries: one to retrieve the parent and another one where a select is performed to retrieve all the children:

Hibernate: 
    select
        d1_0.department_id,
        d1_0.name 
    from
        department d1_0 
    where
        d1_0.department_id=?
Hibernate: 
    select
        e1_0.department_department_id,
        e1_1.employee_id,
        d1_0.department_id,
        d1_0.name,
        e1_1.name,
        e1_1.surname 
    from
        department_employees e1_0 
    join
        employee e1_1 
            on e1_1.employee_id=e1_0.employees_employee_id 
    left join
        department d1_0 
            on d1_0.department_id=e1_1.department_id 
    where
        e1_0.department_department_id=?

Conclusion

In this article, we have seen the usage of FetchMode in Hibernate with Spring Data, which helps us retrieve data according to our needs. These approaches allow us to refine the information returned by the database, leading to better optimization and performance.

If you need more information, you can leave us a comment or send an email to refactorizando.web@gmail.com You can also contact us through our social media channels on Facebook or twitter and we will be happy to assist you!!

Leave a Reply

Your email address will not be published. Required fields are marked *