Ответ
Ленивая загрузка (Lazy Loading) — это стратегия Hibernate, при которой связанные сущности или коллекции не загружаются из базы данных сразу при загрузке родительской сущности, а откладываются до момента первого обращения к ним. Это оптимизация по умолчанию для ассоциаций @OneToMany и @ManyToMany.
Как это реализовано: Hibernate возвращает не настоящую коллекцию или объект, а прокси-объект. При первом вызове метода геттера прокси инициирует загрузку реальных данных из БД.
Пример настройки:
@Entity
public class Order {
@Id
private Long id;
// Ленивая загрузка коллекции (значение по умолчанию для @OneToMany)
@OneToMany(fetch = FetchType.LAZY, mappedBy = "order")
private List<OrderItem> items; // Прокси, а не реальный список
}
@Entity
public class OrderItem {
@Id
private Long id;
// Для @ManyToOne по умолчанию EAGER, но часто меняют на LAZY
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "order_id")
private Order order;
}
Типичное использование:
// Сессия открыта
Order order = session.get(Order.class, 1L); // SELECT * FROM order WHERE id=1
// Пока обращений к items нет, запроса не происходит.
System.out.println(order.getItems().size()); // Тут выполняется: SELECT * FROM order_item WHERE order_id=1
Критически важное ограничение — LazyInitializationException: Это исключение возникает при попытке ленивой загрузки вне контекста открытой сессии Hibernate (Session) или транзакции (в зависимости от конфигурации).
Order order = session.get(Order.class, 1L);
session.close(); // Сессия закрыта
order.getItems().size(); // LazyInitializationException!
Способы решения проблемы:
- Инициализация внутри сессии: Использовать
Hibernate.initialize(proxy). - JOIN FETCH в запросе: Явно загрузить данные в одном запросе.
String jpql = "SELECT o FROM Order o JOIN FETCH o.items WHERE o.id = :id"; - EntityGraph: Задать граф загрузки сущности.
- Паттерн Open Session in View (OSIV): Держать сессию открытой на время всего HTTP-запроса (имеет свои недостатки и требует аккуратной настройки).
Выбор стратегии: Используйте FetchType.EAGER только для связей, которые всегда нужны вместе с родительской сущностью. В остальных случаях LAZY — предпочтительный выбор для производительности.