Ответ вслух Middle Hibernate: N+1, lazy, кеш обновлено

LazyInitializationException

Вопрос

У вас LazyInitializationException при отдаче ответа из контроллера. Какие есть варианты решения и какой вы выберете?

Попробуйте сами

Ответьте вслух за 2 минуты, как на собесе. Потом сверьтесь с тезисами: что прозвучало, а что нет.

Показать ответ и разбор

Коротко

Исключение значит, что ленивую связь трогают после закрытия транзакции, обычно при сериализации сущности в контроллере.

Что должно прозвучать в ответе

  • Причина: ленивая связь, контекст закрыт после транзакции

  • Плохие решения: EAGER, включить OSIV, Hibernate.initialize везде

  • Хорошее: загрузить нужное в сервисе через join fetch или EntityGraph

  • Возвращать DTO, собранный внутри транзакции

  • Проекции для read-моделей

Что могут спросить следом

  • Почему OSIV не лучшее решение?
  • Что такое enable_lazy_load_no_trans и почему он опасен?

Разбор

Исключение значит, что ленивую связь трогают после закрытия транзакции, обычно при сериализации сущности в контроллере. Быстрые «решения» плохи: EAGER делает загрузку всегда и порождает N+1, включённый OSIV держит соединение весь запрос и прячет запросы, а hibernate.enable_lazy_load_no_trans открывает новую сессию на каждую ленивую связь, это N+1 без транзакции. Правильно определить, что нужно экрану, и загрузить это в сервисе внутри транзакции: join fetch или @EntityGraph, а наружу вернуть DTO, собранный там же. Для списков удобны DTO-проекции, они вообще не создают сущностей.

Ответьте сами, а не прочитайте

В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.