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.

Join fetch with Spring Data

In a previous article, we saw that to avoid the LazyInitializationException issue, we can use Join Fetch in JPA with Spring Data. Using this option helps us maintain good application performance by reducing the number of queries.

Let’s start by understanding the difference between Join and Join Fetch in JPA.

Difference between Join Fetch and Join in JPA

Both statements are used to perform a JOIN on another table, combining two tables with a common identifier. However, there is a fundamental difference between the two, as shown in the following example:

Select * FROM Employee emp
         JOIN emp.department dep 
SELECT * FROM Employee emp
         JOIN FETCH emp.department dep

The difference is that the first query will only return the Employees, while the second query will return both the Employees and the related Departments.

By using the second option, we avoid making additional queries to obtain the Departments of each Employee.

When using the first example, we would encounter the typical N+1 query problem.

Let’s see a complete example.

Example of Join Fetch with Spring Data

To see the complete example, you can check it here.

Configuration of Spring Boot properties file to display queries in H2

Let’s add two properties to display queries in the console:

spring:
  jpa:
    show-sql: true
    properties:
      hibernate:
        format_sql: true

Entity generation

Let’s generate two entities with a 1 .. N relationship between Department and Employee. We’ll use @ElementCollection for the following entities, but it could also be done with @OneToMany, for example:

@Getter
@Setter
@Entity
public class Department {

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

  private String name;

  @ElementCollection
  private List<Employee> employees;

}
@Embeddable
@Getter
@Setter
public class Employee {

    private String name;

    private String surname;

}

Once we’ve created the entities, let’s create a repository where we’ll define a query using @Query with Join Fetch:

public interface DepartmentRepository extends JpaRepository<Department, String> {

  @Query("SELECT DISTINCT department FROM Department department " + "JOIN FETCH department.employees employees")
  List<Department> retrieveAll();
}

Next, we’ll create two tests to verify the number of queries generated and to check that using Join Fetch will result in a single query.

@SpringBootTest
@Slf4j
public class DepartmentRepositoryIT {

  @Autowired
  private DepartmentRepository departmentRepository;

  @Test
  @Transactional
  public void withoutJoinFetch() {
    List<Department> departments = departmentRepository.findAll();

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

  }

  @Test
  @Transactional
  public void withJoinFetch() {
    List<Department> departments = departmentRepository.retrieveAll();

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

}

When running the above tests, we’ll see that executing the method that uses Join Fetch results in a single query:

Hibernate: 
    select
        distinct d1_0.id,
        e1_0.department_id,
        e1_0.name,
        e1_0.surname,
        d1_0.name 
    from
        department d1_0 
    join
        department_employees e1_0 
            on d1_0.id=e1_0.department_id

On the other hand, executing the method that uses the findAll() method of JPA will result in exactly two queries, one for department and one for employee:

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

As we can see, the test that did not use Join Fetch will perform an N+1 query, meaning one query for the parent object and as many queries as there are child objects.

Conclusion

In this article, we have seen how Join Fetch works in JPA with Spring Data, which is important to know as it can affect the performance of our applications.

Another article that might interest you is the use of FetchMode in Hibernate.

If you want to download the complete example, you can do so from here.

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 *