Lazy vs eager fetching
Control when Hibernate goes back to the database to load an association.
Open this lesson in the learning hubKey points
- Lazy gives you a proxy now and a SELECT on first use. Eager loads the association immediately, every time.
- The defaults are inconsistent:
@ManyToOneand@OneToOneare EAGER, collections are LAZY. Override the singles to LAZY. - Eager is a promise you cannot take back: every query that loads the entity drags the association along, even when nobody reads it.
- Touching a lazy association after the transaction ends throws
LazyInitializationException. Load what the caller needs while the context is open. - Spring Boot leaves
spring.jpa.open-in-viewon, hiding that error by holding the context open during rendering. Turn it off. - Lazy on the inverse side of a
@OneToOneneeds bytecode enhancement - Hibernate must query to learn whether the row exists.
Example
@Entity
public class Book {
@ManyToOne(fetch = FetchType.LAZY) // default is EAGER - always override
@JoinColumn(name = "author_id")
private Author author;
@OneToMany(mappedBy = "book") // collections are LAZY already
private List<Review> reviews = new ArrayList<>();
}
// Then fetch deliberately, per use case:
@Query("select b from Book b join fetch b.author where b.id = :id")
Optional<Book> findWithAuthor(@Param("id") Long id);
Make everything lazy, then fetch on purpose for each use case.
This is a reading copy. The full lesson — with the visual explainer, the interactive lab and a Run button for the code — lives in the Hibernate course, and every lesson in it is listed on the Hibernate contents page.