Careeroza
LAZY vs EAGER
Two Loading Strategies
- EAGER: the association is loaded together with the entity, always, whether you use it or not.
- LAZY: Hibernate puts a placeholder (a proxy for a single entity, a persistent collection for a list) and runs the SELECT only when you first access it.
| Annotation | Default fetch type | Recommended |
|---|---|---|
@ManyToOne | EAGER | LAZY |
@OneToOne | EAGER | LAZY |
@OneToMany | LAZY | LAZY |
@ManyToMany | LAZY | LAZY |
@ElementCollection | LAZY | LAZY |
Tip: Rule of thumb used by the Hibernate team: make every association LAZY, and decide per query what to load. EAGER is decided once in the mapping and cannot be switched off for one query.
Seeing LAZY Loading in the Log
@Transactional(readOnly = true)
public void show(Long id) {
Product p = productRepository.findById(id).orElseThrow(); // SELECT products only
System.out.println(p.getName());
Category c = p.getCategory(); // proxy, no SQL yet
System.out.println(c.getId()); // id is known: still no SQL
System.out.println(c.getName()); // first real access: SELECT categories
}Console output
productService.show(7L);Example output
DEBUG org.hibernate.SQL : select p1_0.id,p1_0.category_id,p1_0.description,p1_0.name,p1_0.price,p1_0.stock from products p1_0 where p1_0.id=? Boat Airdopes 141 3 DEBUG org.hibernate.SQL : select c1_0.id,c1_0.name from categories c1_0 where c1_0.id=? Electronics
What EAGER Costs
With @ManyToOne left EAGER, findById joins the category in one SQL. That looks good, but every query that loads products, even one that only needs names, now also loads categories. In JPQL queries, EAGER associations are not joined but loaded with extra SELECTs afterwards, which is the N+1 problem in disguise.
-- findById with EAGER category: a join
select p1_0.id,p1_0.category_id,c1_0.id,c1_0.name,p1_0.description,p1_0.name,p1_0.price,p1_0.stock
from products p1_0 join categories c1_0 on c1_0.id=p1_0.category_id where p1_0.id=?
-- "select p from Product p" with EAGER category: one extra select per distinct category
select p1_0.id,p1_0.category_id,p1_0.description,p1_0.name,p1_0.price,p1_0.stock from products p1_0
select c1_0.id,c1_0.name from categories c1_0 where c1_0.id=?
select c1_0.id,c1_0.name from categories c1_0 where c1_0.id=?
select c1_0.id,c1_0.name from categories c1_0 where c1_0.id=?