Understanding FetchType, FetchMode, and Lazy Loading in JPA with Hibernate
Java Persistence API (JPA) is a powerful Java framework for managing relational data in applications. When working with JPA, it's crucial to understand how data is fetched from the database and how to control this behavior effectively. In this article, we will delve into concepts like FetchType
, FetchMode
, and the intricacies of lazy loading, using Hibernate as the JPA provider.
FetchType in JPA
FetchType
is an attribute that determines how related entities or collections are loaded when querying an entity with relationships. There are two primary FetchType
options:
EAGER: Eager loading retrieves related entities or collections immediately when the parent entity is fetched. This means all associated data is fetched in a single database query.
LAZY: Lazy loading delays the retrieval of related entities or collections until you explicitly access them. This can enhance performance by avoiding unnecessary data loading.
FetchMode in Hibernate
FetchMode
is specific to Hibernate, a popular JPA provider, and further refines the behavior of loading related entities or collections. Hibernate offers several FetchMode
options:
SELECT: This is the default fetch mode. It selects related entities using separate SQL queries, often referred to as the "N+1 query problem."
JOIN:
JOIN
fetch mode generates a single SQL query withJOIN
statements to retrieve both the parent and related entities, reducing the number of SQL queries.SUBSELECT: The
SUBSELECT
fetch mode first retrieves the parent entity and then issues a separate SQL query to load all related entities using a subquery. This approach is efficient for collections.BATCH:
BATCH
fetch mode is primarily used for collections. It loads related collections in batches using additional SQL queries, which is efficient for large collections.
Example: OneToMany Relationship
Let's explore these concepts with an example involving two entities connected by a OneToMany
relationship: Author
and Book
. An Author
can have multiple Book
entities associated with them.
@Entity
public class Author {
@Id
private long id;
private String name;
// EAGER Fetch with SELECT Mode
@OneToMany(mappedBy = "author", fetch = FetchType.EAGER)
@Fetch(FetchMode.SELECT)
private List<Book> booksEagerSelect;
// EAGER Fetch with JOIN Mode
@OneToMany(mappedBy = "author", fetch = FetchType.EAGER)
@Fetch(FetchMode.JOIN)
private List<Book> booksEagerJoin;
// LAZY Fetch with SELECT Mode
@OneToMany(mappedBy = "author", fetch = FetchType.LAZY)
@Fetch(FetchMode.SELECT)
private List<Book> booksLazySelect;
// LAZY Fetch with JOIN Mode
@OneToMany(mappedBy = "author", fetch = FetchType.LAZY)
@Fetch(FetchMode.JOIN)
private List<Book> booksLazyJoin;
// LAZY Fetch with SUBSELECT Mode
@OneToMany(mappedBy = "author", fetch = FetchType.LAZY)
@Fetch(FetchMode.SUBSELECT)
private List<Book> booksLazySubselect;
// LAZY Fetch with BATCH Mode
@OneToMany(mappedBy = "author", fetch = FetchType.LAZY)
@Fetch(FetchMode.BATCH)
private List<Book> booksLazyBatch;
// getters and setters
}