LAZY vs EAGER Loading in JPA — Defaults, OSIV, and the Right Fix
Fast recall
Quick revision
Core answer
@ManyToOne and @OneToOne = EAGER; @OneToMany and @ManyToMany = LAZY. The correct production strategy is LAZY everywhere + opt-in per query — explicitly override @ManyToOne(fetch=LAZY) and @OneToOne(fetch=LAZY), then use JOIN FETCH, @EntityGraph, @BatchSize, or DTO projections per use case. EAGER on `@OneToMany` is always wrong — Cartesian-product JOINs, broken pagination, no per-query opt-out. The canonical bug is LazyInitializationException — accessing a proxy after the transaction ended. Spring Boot's `spring.jpa.open-in-view=true` default hides this by silently firing N+1 in Jackson serialization. Always `open-in-view=false` in production.Whether the candidate understands fetch strategies, default values per association type, and how they interact with session lifecycle and OSIV
Using EAGER everywhere to avoid `LazyInitializationException` — over-fetching and Cartesian products result
Discuss default fetch types, the OSIV anti-pattern, DTO projections, and the LAZY-everywhere + opt-in-per-query pattern
Interview-ready guide
Interview answer
Fetch strategy controls whether Hibernate loads associations immediately with the parent or defers until access. Getting it wrong causes either N+1 queries or LazyInitializationException.
Defaults by association:
@ManyToOne,@OneToOne-> EAGER by default@OneToMany,@ManyToMany-> LAZY by default
The EAGER problem:
- EAGER associations always trigger a load, even when not needed
- A JOIN FETCH on a LAZY association loads it once; an EAGER association adds a second SELECT
- Rule:
fetch = FetchType.LAZYon every association; fetch eagerly per query when needed
LAZY + access outside transaction = `LazyInitializationException`:
- Proxy needs an open
EntityManagerto initialize - Transaction ends,
EntityManagercloses, proxy throws - Fix: JOIN FETCH,
@EntityGraph, or DTO — neveropen-in-view=truein production
The pattern:
- LAZY everywhere as the default
@EntityGraphfor detail views- DTO projections for list views and APIs
@BatchSizefor any residual N+1spring.jpa.open-in-view=falseto surface bugs in staging, not production
LAZY vs EAGER Loading in JPA — Defaults, OSIV, and the Right Fix
Direct Answer
LAZY defers SQL for an association until first accessed — Hibernate returns a proxy. EAGER fetches the association in the same query whether you need it or not. JPA defaults: @ManyToOne and @OneToOne = EAGER; @OneToMany and @ManyToMany = LAZY. The correct production strategy is LAZY everywhere + opt-in per query — explicitly override @ManyToOne(fetch=LAZY) and @OneToOne(fetch=LAZY), then use JOIN FETCH, @EntityGraph, @BatchSize, or DTO projections per use case. EAGER on @OneToMany is always wrong — Cartesian-product JOINs, broken pagination, no per-query opt-out. The canonical bug is LazyInitializationException — accessing a proxy after the transaction ended. Spring Boot's spring.jpa.open-in-view=true default hides this by silently firing N+1 in Jackson serialization. Always open-in-view=false in production.
Common Mistakes & Pitfalls
Using EAGER everywhere to avoid LazyInitializationException — over-fetching and Cartesian products result
Check your understanding
Answer these without looking back at the article.
- What is Open Session In View and why is it generally considered an anti-pattern?
- How do you override the default fetch type on `@ManyToOne` to LAZY?
- If you disable OSIV and still need an association in a `@RestController`, what is the cleanest pattern?
- Why doesn't LAZY on `@OneToOne` inverse side work without bytecode enhancement?
Related interview prep categories
2Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.