Почему возникает ошибка при вызове ленивой загрузки коллекции в контроллере после закрытия сессии и как ее избежать
Что проверяют
Понимаете ли вы, что ленивая коллекция это заместитель, живущий только внутри открытого контекста персистентности, и где в Spring проходят границы транзакции. Проверяют не знание аннотации, а умение спроектировать загрузку данных.
Как отвечать
Связи к многим по умолчанию ленивые. Вместо коллекции в сущность подставляется обёртка, которая при первом обращении идёт в базу через свою сессию. Если транзакция открывалась на методе сервиса, к возврату в контроллер сессия уже закрыта, и первое же обращение к коллекции даёт LazyInitializationException: could not initialize proxy, no Session.
Правильный ход: загрузить нужное, пока контекст открыт.
join fetchв запросе:select distinct a from Author a join fetch a.books where a.id = :id;@EntityGraphнад методом репозитория, когда запрос генерируется по имени;- проекция сразу в DTO, тогда заместитель вообще не появляется;
Hibernate.initialize(...)внутри транзакции как точечное средство.
Сборку ответа полезно завершать внутри транзакционного сервиса и отдавать наружу DTO, а не сущность.
Отдельно скажите, чего делать не стоит. Жадная загрузка на связи включается всегда, включая списочные экраны, и приносит с собой лишние запросы по каждой строке. Режим удержания сессии до конца формирования ответа убирает исключение, но оставляет причину.
Где спотыкаются
Переключают связь на жадную загрузку и считают вопрос закрытым. Решение глобальное: коллекция едет при любом чтении сущности, а две жадные коллекции типа списка дают уже ошибку при попытке забрать их одним запросом.
Полагаются на удержание сессии до конца отрисовки ответа, потому что так работает настройка по умолчанию. Соединение занято дольше, запросы переезжают в слой представления, где их никто не считает, а падение при сериализации происходит уже после фиксации транзакции.
Возвращают сущности прямо из контроллера. Сериализатор обходит граф, дёргает геттеры и инициализирует всё подряд либо спотыкается о заместителя, а заодно в ответ утекают поля, которых там быть не должно.