Hibernate Lazyloading не работает с методом @Transactional

Я столкнулся со столь обсуждаемым ""

Я работаю над приложением весенней загрузки, используя спящий режим.

Насколько я знаю, если атрибут объекта помечен как FetchType.LAZY, необходимо иметь сеанс Hibernate, чтобы иметь возможность инициировать соответствующий запрос для получения связанного объекта.

Ниже приведен метод, который извлекает список сущностей из родительской сущности:

@Transactional
public List<Portfolio> getSharedPortfolios(String userName){
    User user = userService.getUserActive(userName);
    List<Portfolio> sharedPortfolios = user.getSharedPortfolios();
    //logger.debug("Number of Shared Portfolios: " + sharedPortfolios.size());  <======
    return sharedPortfolios;
}

Метод getSharedPortfolios вызывается из контроллера и получает «org.hibernate.LazyInitializationException», а затем пытается получить доступ к этому списку (PersistentBag)

Поскольку метод getSharedPortfolios аннотирован аннотацией @Transactional, я ожидал, что при выполнении user.getSharedPortfolios() (sharedPortfolios — это список отложенной выборки) соответствующий список инициализируется. Но этого не происходит.

Может кто-нибудь объяснить мне, почему? И почему, если я раскомментирую строку журнала, которая печатает размер этого PersistentBag, исключение не выдается?

Нужно ли мне в этом случае явно инициализировать его с помощью EntityManager?

Большое спасибо.

1
0
767
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Когда вы вызываете List<Portfolio> sharedPortfolios = user.getSharedPortfolios();, значение, присвоенное sharedPortfolios, является ленивым прокси.

Если вы просто вернете sharedPortfolios и получите доступ к нему вне вашего метода @Transactional, вы получите LazyInitializationException

С другой стороны, если вы обращаетесь к sharedPortfolios в своем методе @Transactional, происходит инициализация, и вы возвращаете уже инициализированные данные.

ИМХО то, что вы описываете, является ожидаемым поведением.

Существует несколько способов принудительного извлечения:

  • граф объектов
  • jpql (выборка)
  • запрос критериев (выборка)
  • доступ к переменной вручную (как показано в вашем примере)

В качестве альтернативы проверьте настройку spring.jpa.open-in-view=true

я не уверен, что это значит

"The getSharedPortfolios method is being called from a controller"

так что это может быть не ваш случай, но аннотация @Transactional не будет работать, если вы вызываете метод getSharedPortfolios из другого метода в том же классе.

Другие вопросы по теме