Какой тип загрузки данных использует JOIN FETCH в JPA/Hibernate?

«Какой тип загрузки данных использует JOIN FETCH в JPA/Hibernate?» — вопрос из категории Hibernate, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

JOIN FETCH в JPQL-запросе JPA/Hibernate принудительно использует жадную загрузку (Eager Loading) для указанных связанных коллекций или сущностей в рамках этого конкретного запроса.

Как это работает: Hibernate формирует один SQL-запрос с JOIN, чтобы сразу загрузить основную сущность и связанные данные, избегая проблемы N+1, даже если для ассоциации установлена ленивая загрузка (FetchType.LAZY).

Пример:

@Entity
public class Order {
    @Id
    private Long id;

    // По умолчанию или явно LAZY
    @OneToMany(mappedBy = "order", fetch = FetchType.LAZY)
    private List<OrderItem> items;
}

// JPQL-запрос с JOIN FETCH
String jpql = "SELECT o FROM Order o JOIN FETCH o.items WHERE o.id = :id";
Order order = entityManager.createQuery(jpql, Order.class)
                          .setParameter("id", 1L)
                          .getSingleResult();
// Коллекция items загружена немедленно в этом запросе

Важно: JOIN FETCH переопределяет стратегию загрузки, указанную в аннотации (LAZY/EAGER), только для данного запроса. Вне этого запроса ассоциация продолжает вести себя согласно своей аннотации.