Список из 100 заказов рендерится вместе с покупателем каждого, и в логе видно 101 SQL-запрос. Какие способы исправят проблему?
- Как исправить N+1 в Spring Data JPA?
JOIN FETCH в @Query, @EntityGraph на методе репозитория или пакетная загрузка (hibernate.default_batch_fetch_size). EAGER не решает — делает проблему постоянной.
- DTO-проекция — выбрать только нужное одним запросом
- JOIN FETCH коллекции с пагинацией — Hibernate пагинирует в памяти
- Обнаруживать — лог SQL и проверка числа запросов в тестах
А ещё @EntityGraph(attributePaths = "customer") — без изменения запроса
Подробно
N+1 возникает потому, что ленивая связь подгружается отдельным запросом на каждую строку. Замена на EAGER — самый частый неверный ответ: количество запросов остаётся тем же, просто они выполняются всегда, включая случаи, когда связь не нужна, и проблема расползается по всему приложению. JOIN FETCH и @EntityGraph решают задачу точечно, в конкретном сценарии, где данные действительно нужны. Пакетная загрузка помогает, когда переписать запрос нельзя. Отдельно стоит помнить про подводный камень JOIN FETCH с несколькими коллекциями: возникает декартово произведение, поэтому больше одной коллекции так не тянут, а используют пакетную загрузку или отдельные запросы. И самый радикальный вариант для чтения — сразу проецировать в DTO.
Что хотят услышать
- Несколько способов исправления.
- Почему EAGER не решение.
- Ловушка пагинации.
Частые ошибки
- Лечить N+1 переводом связей в EAGER.
- Делать JOIN FETCH сразу по двум коллекциям.
Проверьте себя
Несколько верных вариантов. Подумайте, потом откройте ответ.
Показать варианты и ответ
- ✓JOIN FETCH в @Query — связи грузятся одним запросом
- ✓@EntityGraph на методе репозитория
- ✓@BatchSize или default_batch_fetch_size — вместо 100 запросов несколько
- ✗Сменить тип связи на EAGER — тогда Hibernate сам подгрузит всех покупателей одним запросом
Что спросят дальше
- Почему JOIN FETCH двух коллекций даёт декартово произведение?
- Чем проекция в DTO выгоднее загрузки сущностей?
Разбор темы
- Spring Data JPA: репозитории и Hibernate
Абстракция репозитория, derived queries и @Query, persistence context и dirty checking, lazy/N+1 и почему DTO, а не entity.
Связанные вопросы
Разбор собеседования с sotto
После собеседования sotto разбирает разговор: оценка, каждый вопрос — хорошо, частично или слабо, чего не хватило в ответе и над чем поработать к следующему разу. Первые 30 минут бесплатно.