Теоретический вопрос о Hibernate Lazy Загрузка - PullRequest
0 голосов
/ 20 марта 2020

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

Так что если у нас есть:

@Entity
public class Payment {

 ...

 @ManyToOne(fetch = FetchType.LAZY)
 private Debtor debtor;

}

Я ожидаю, что когда я получаю платеж из базы данных, Hibernate устанавливает заполнитель в атрибуте должника и выбирает должника только тогда, когда это строго требуется .

Так что если я использую метод получения, чтобы получить Должник из моего Платежного объекта:

Debtor debtor = payment.getDebtor();

Я ожидаю, что потоки блокируются, пока Hibernate не выполнит запрос SELECT и не возвратит объект Debtor.

Так почему, черт возьми, я всегда получите исключение HibernateLazyLoading , которое обязывает меня написать пользовательский запрос выборки в PaymentRepository, замедляя мой первоначальный запрос AS. Я бы использовал EAGER FetchType ?

Так почему же это FetchType.LAZY существует, если оно не работает так, как ожидалось?

Ответы [ 2 ]

4 голосов
/ 20 марта 2020

Я хотел бы указать ответ @Andronicus, потому что ответ не точный.

LazyInitializationException

Он не связан строго с @Transactional, транзакциями или открытием / закрытые соединения. Поведение довольно просто (есть псевдокод ниже)

Без LazyInitializationException

Context context = Hibernate.openPersistentContext();

Payment payment = context.getById(1L, Payment.class);
Debtor debtor = payment.getDebtor();

Hibernate.closePersistentContext();

С LazyInitializationException

    Context context = Hibernate.openPersistentContext();

    Payment payment = context.getById(1L, Payment.class);

    Hibernate.closePersistentContext();

    Debtor debtor = payment.getDebtor();

Вопросы

Так почему, черт возьми, я всегда получаю исключение HibernateLazyLoading, которое обязывает меня написать пользовательский запрос на выборку в репозитории PaymentRepository, замедляя мой первоначальный запрос, поскольку я бы использовал EAGER FetchType?

Потому что Hibernate.closePersistentContext() произошло где-то раньше.

Так почему же этот FetchType.LAZY существует, если он не работает так, как ожидалось?

Потому что нам не всегда нужен полностью net графа сущностей. Мы можем использовать JPQL (HQL), критерии и прогнозы для загрузки частей сущности. Нам нужно объяснить Hibernate, как связаны сущности, поэтому нам нужно добавить ассоциации, например @ManyToOne.

Здесь есть небольшая проблема: отображение служит для двух целей

  1. Объясните Hibernate, как связаны сущности
  2. Сохраните / Загрузите сущности

Итак, самый простой способ отключить загрузку от сопоставления объектов - это FetchType.LAZY.

Простое правило

Всегда используйте FetchType.LAZY везде и извлекайте необходимые части графа сущностей в том месте, где он необходим.

3 голосов
/ 20 марта 2020

Так почему, черт возьми, я всегда получаю исключение HibernateLazyLoading, которое обязывает меня написать пользовательский запрос на выборку в репозитории Payment, замедляя мой первоначальный запрос, поскольку я бы использовал EAGER FetchType?

Это потому, что это предложение не совсем верно:

Я ожидаю, что при получении платежа из базы данных Hibernate устанавливает заполнитель в атрибуте должника и извлекает должника только тогда, когда это строго требуется.

Debtor действительно будет получено, если к нему обращаются, но только если оно может быть получено. Если вы запустите его в транзакции (например, с помощью аннотации метода с @Transactional), ошибка не возникнет, так как соединение с базой данных не возвращается в пул / закрыто.

В вашем случае данные извлекаются, Debtor упаковывается в прокси и соединение теряется. Если вы попытаетесь получить к нему доступ, выдается LazyInitializationException.

PS: не рекомендуется использовать транзакции, чтобы избежать LazyInitializationException из-за проблем с производительностью, которые могут возникнуть. Если вы выбираете родителя, а затем выполняете итерацию по нескольким (скажем, N) лениво извлеченным дочерним элементам, N + 1 запросы к базе данных снимаются.

...