JavaScript Required

We're sorry, but we doesn't work properly without JavaScript enabled.

Looking for an Expert Development Team? Take two weeks Trial! Try Now

Overview of FetchMode in Spring Data JPA

Overview

FetchMode in Spring Data JPA

Current tutorial we will get to know what is fetchMode, how to it is used to fetch the entity, introduction to @org.hibernate.annotations.Fetch annotation.

Setting up the Example

As an example we will use Customer entity with two properties, id and set of orders.

Customer.java @Entity @Table(name = "CUSTOMER") public class Customer { @Id @GeneratedValue private Long id; @OneToMany @Fetch(FetchMode.SELECT) private Set < Orders > orders = new HashSet < Orders > (); //setters and getters }

Next we will create Orders entity, consisting of Customer entity as a reference.

Orders.java @Entity @Table(name = "ORDERS") public class Orders { @Id @GeneratedValue private Long id; private String name; @ManyToOne @JoinColumn(name = "customer_id") private Customer customer; //setters and getters }

Next using test class, we will understand the usage of @Fetch annotation.

From fetching the customer details from database, we are using Hibernate session.

Below is the code to get customer details along with orders from database.

Customer customter = session.get(Customer.class, id); Set<Order> orders = customer.getOrders();

But there can be different ways to fetch the orders from database, either we can join with Customer entity to get the details, or generate single query for we can use another query to get all the order details.

1) FetchMode.SELECT: it is the default strategy, it will be used for fetching dependent lazily.

@OneToMany @Fetch(FetchMode.SELECT) private Set<Orders> orders = new HashSet<Orders>();

Fetch is used describe how hibernate should retrieve the dependent property when we lookup for a parent entity.

Using SELECT Hibernate will fetch orders entity lazily.

For suppose we want to fetch all the customers and their orders the code will look like below:

Session session = sessionFactory.openSession(); List < Customer > cusomter1 = session.createCriteria(Customer.class).list(); for (Customer cus: cusomter1) { assertTrue(cus.getOrders().stream().allMatch(order - > order.getCustomer().getId() > 0)); }

This will result the below generated SQL statements.

Hibernate: select this_.id as id1_0_0_ from CUSTOMER this_ Hibernate: select orders0_.Customer_id as Customer1_1_0_, orders0_.orders_id as orders_i2_1_0_, orders1_.id as id1_2_1_, orders1_.customer_id as customer3_2_1_, orders1_.name as name2_2_1_, customer2_.id as id1_0_2_ from CUSTOMER_ORDERS orders0_ inner join ORDERS orders1_ on orders0_.orders_id=orders1_.id left outer join CUSTOMER customer2_ on orders1_.customer_id=customer2_.id where orders0_.Customer_id=? (Repeated for each customer)

For each customer it will fetch the orders using individual query, this will result into very well-known n+1 select problem. First query is used to fetch the customers, and n queries are used for fetching each customer.

2) @BatchSize: Fetch mode as an optional configuration to specify the batch size, instead of retrieving the each customer order separately, Hibernate will fetch orders using batches. Using @BatchSize we can configure the batch size. This way we can decrease the number of queries required to fetch the orders.

@OneToMany @Fetch(FetchMode.SELECT) @BatchSize(size = 2) private Set<Orders> orders = new HashSet<Orders>(); And generated Hibernate SQL statements look like below: Hibernate: select orders0_.Customer_id as Customer1_1_2_, orders0_.orders_id as orders_i2_1_2_, orders1_.id as id1_2_0_, orders1_.customer_id as customer3_2_0_, orders1_.name as name2_2_0_, customer2_.id as id1_0_1_ from CUSTOMER_ORDERS orders0_ inner join ORDERS orders1_ on orders0_.orders_id=orders1_.id left outer join CUSTOMER customer2_ on orders1_.customer_id=customer2_.id where orders0_.Customer_id in (?, ?)

3) FetchMode.JOIN: It is almost same eager loading, the orders and customer entities are queries using same query.

@OneToMany @Fetch(FetchMode.JOIN) private Set<Orders> orders = new HashSet<Orders>();

In this case for all required entities only single query is executed.

Hibernate generated SQL statement will look like this:

Hibernate: select this_.id as id1_0_2_, orders2_.Customer_id as Customer1_1_4_, orders3_.id as orders_i2_1_4_, orders3_.id as id1_2_0_, orders3_.customer_id as customer3_2_0_, orders3_.name as name2_2_0_, customer4_.id as id1_0_1_ from CUSTOMER this_ left outer join CUSTOMER_ORDERS orders2_ on this_.id=orders2_.Customer_id left outer join ORDERS orders3_ on orders2_.orders_id=orders3_.id left outer join CUSTOMER customer4_ on orders3_.customer_id=customer4_.id

4) FetchMode.SUBSELECT: it is used only if the nested property is type of collection.

@OneToMany @Fetch(FetchMode.SUBSELECT) private Set<Orders> orders = new HashSet<Orders>();

Using this fetchmode, only 2 queries are executed, one for fetching the customers, and one more query for fetching all customer orders.

And the Hibernate Generated queries look like below:

Hibernate: select this_.id as id1_0_0_ from CUSTOMER this_ Hibernate: select orders0_.Customer_id as Customer1_1_2_, orders0_.orders_id as orders_i2_1_2_, orders1_.id as id1_2_0_, orders1_.customer_id as customer3_2_0_, orders1_.name as name2_2_0_, customer2_.id as id1_0_1_ from CUSTOMER_ORDERS orders0_ inner join ORDERS orders1_ on orders0_.orders_id=orders1_.id left outer join CUSTOMER customer2_ on orders1_.customer_id=customer2_.id where orders0_.Customer_id in (select this_.id from CUSTOMER this_)

FetchMode vs. FetchType

In general, FetchMode defines how Hibernate will fetch the data (by select, join or subselect). FetchType, on the other hand, defines whether Hibernate will load data eagerly or lazily.

The exact rules between these two are as follows:

  • 1) if the code doesn't set FetchMode, the default one is JOIN and FetchType works as defined
  • 2) with FetchMode.SELECT or FetchMode.SUBSELECT set, FetchType also works as defined
  • 3) with FetchMode.JOIN set, FetchType is ignored and a query is always eager

Necessary for me to keep in mind to connect FetchType when java programmers should be able to solve simple problems.

Conclusion

In this tutorial we learned about what FetchMode is, how Hibernate is using internally to fetch entity mappings, and different types of FetchModes and their usage, and finally we understood the differences between Fetch Mode and FetchType.

Source code: Hibenet Example Code

 
NSS Note

Some of our clients

team