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:

  1. 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.

  2. 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:

  1. SELECT: This is the default fetch mode. It selects related entities using separate SQL queries, often referred to as the "N+1 query problem."

  2. JOIN: JOIN fetch mode generates a single SQL query with JOIN statements to retrieve both the parent and related entities, reducing the number of SQL queries.

  3. 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.

  4. 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
}