Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why Hibernate sometimes ignores FetchMode.JOIN?

I have an entity with a @ManyToOne relation, which I'd like to retrieve with a single query, thus using @Fetch(FetchMode.JOIN). Sometimes Hibernate doesn't respect that and issues N+1 SELECTs. With sometimes I mean that since I don't know what triggers it, I have cases which on the same class for different queries this could happen or not.

This is a simplified entity with the annotations I use:

@Entity
public class Employee {

    @ManyToOne
    @Fetch(FetchMode.JOIN)
    private Department department;

}

With

CriteriaQuery<Employee> criteriaQuery = criteriaBuilder.createQuery(Employee.class);

Root<Employee> root = criteriqQuery.from(Employee.class);

TypedQuery<Employee> typedQuery = entityManager.createQuery(criteriaQuery);

List<Employee> employees = typedQuery.getResultList();

I would expect a single query to fetch both Employee and its Department, something like

select ... from Employee join Department on ...

instead I get a first select for all N Employees and then N SELECTs for all Departments (consider no cache).

I've found many similar questions, but their answers suggest workarounds and do not explain why this is happening. Please, avoid answers suggesting to use lazy loading: it's not what I'm asking.

like image 920
Giovanni Lovato Avatar asked Apr 22 '16 14:04

Giovanni Lovato


People also ask

What is FetchMode in Hibernate?

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.

What are the different fetching ways in Hibernate?

Hibernate defines the following fetching strategies: Join fetching: Hibernate retrieves the associated instance or collection in the same SELECT , using an OUTER JOIN . Select fetching: a second SELECT is used to retrieve the associated entity or collection.

What is fetch in JPA?

The FETCH keyword of the JOIN FETCH statement is JPA-specific. It tells the persistence provider to not only join the 2 database tables within the query but to also initialize the association on the returned entity. You can use it with a JOIN and a LEFT JOIN statement.


1 Answers

The rule is quite simple: Queries ignore fetch modes. When you write a query, you are telling what is joined and what is not joined.

Fetch mode is only taken into account when entity is loaded with methods like EntityManager.find(class, id) or when navigating through some other entity graph and loading its associations.

like image 57
Dragan Bozanovic Avatar answered Oct 14 '22 14:10

Dragan Bozanovic