Что такое fetch types в Hibernate и какие они бывают
Что проверяют
Знаете ли вы значения по умолчанию в JPA и умеете ли управлять загрузкой связей так, чтобы не получить N+1 и LazyInitializationException. Следом обычно спрашивают, как вы находите N+1 и почему EAGER не решение.
Как отвечать
FetchType из jakarta.persistence отвечает на вопрос, когда загружать связь:
EAGER: связанная сущность загружается вместе с владельцем, всегда и во всех запросах. По умолчанию у@ManyToOneи@OneToOne;LAZY: вместо связи подставляется прокси или обёртка над коллекцией. Запрос уходит при первом обращении и только пока открыта сессия. По умолчанию у@OneToManyи@ManyToMany.
Отдельно стоит @Fetch с FetchMode из самого Hibernate: JOIN, SELECT, SUBSELECT. FetchType решает, когда грузить, FetchMode решает, каким SQL.
Рабочая практика в проектах на Spring Boot 3 и Hibernate 6: все связи объявлять ленивыми, включая @ManyToOne(fetch = FetchType.LAZY), а нужные данные подгружать под конкретный сценарий:
JOIN FETCHв JPQL-запросе;@EntityGraphна методе репозитория Spring Data JPA;@BatchSizeилиhibernate.default_batch_fetch_size, чтобы N запросов превратились в несколько запросов сIN;- DTO-проекции, когда сущность целиком не нужна.
N+1 находят по логам SQL, по статистике Hibernate (hibernate.generate_statistics) или тестами, которые проверяют число запросов.
Где спотыкаются
Советуют EAGER для «часто нужных» связей. Это не спасает: при select o from Order o Hibernate грузит EAGER-связи отдельными запросами после основного, то есть получается тот же N+1, и платить за него приходится даже там, где связь не нужна.
Лечат LazyInitializationException через spring.jpa.open-in-view=true (в Spring Boot это значение по умолчанию, при старте выводится предупреждение) или hibernate.enable_lazy_load_no_trans. Оба варианта прячут проблему: запросы уходят из слоя представления, а соединение с базой занято на всё время обработки запроса.
Делают JOIN FETCH коллекции вместе с пагинацией. Hibernate выгружает все строки и режет страницу в памяти, с предупреждением в логе. А два JOIN FETCH по коллекциям типа List дают MultipleBagFetchException.