Короткий ответ
EAGER и LAZY — две стратегии загрузки ассоциаций, определяющие, когда данные связей извлекаются из базы. При жадной загрузке связанные данные приходят сразу вместе с основной сущностью; при ленивой — Hibernate подставляет прокси или коллекцию-обёртку, а запрос выполняется только в момент реального обращения к свойству. Стратегия задаётся атрибутом fetch аннотации связи.
Как это работает подробнее
Ленивая загрузка экономит память и число запросов, когда связь может не понадобиться, но требует открытой сессии в момент обращения к свойству. Если обратиться к ленивой связи, когда Session или persistence context уже закрыт, Hibernate выбрасывает LazyInitializationException.
- По умолчанию:
@ManyToOne— EAGER,@OneToManyи@ManyToMany— LAZY. - LazyInitializationException: «could not initialize proxy - no Session» — возникает, например, при чтении сущности в контроллере вне границ
@Transactional, когда сессия из сервиса уже закрыта. - Решения: обращаться к ленивым связям внутри транзакции или открытой сессии; подгружать их одним запросом через
JOIN FETCHв JPQL/HQL или через@EntityGraph; осознанно менять стратегию на EAGER там, где это уместно. - Open Session in View: держит сессию открытой на уровне представления; обычно считается анти-паттерном из-за лишних запросов и удержания соединения.
Пример кода
Department.java
@Entity
public class Department {
@Id
private Long id;
@OneToMany(mappedBy = "department", fetch = FetchType.LAZY)
private List<Employee> employees;
@ManyToOne(fetch = FetchType.EAGER)
private Company company;
}