@LazyCollection в Hibernate
Аннотация @LazyCollection управляет стратегией ленивой загрузки для коллекций (например, @OneToMany, @ManyToMany) в Hibernate. Определяет, когда и как должны загружаться связанные сущности.
Пакет: org.hibernate.annotations
Применяется к: полям-коллекциям (List, Set, Map и др.) с аннотациями @OneToMany или @ManyToMany.
Параметры и настройки
Аннотация принимает один обязательный параметр — value, который может быть одним из следующих вариантов:
LazyCollectionOption.TRUE (по умолчанию для @OneToMany и @ManyToMany):
Коллекция загружается лениво (при первом обращении).
Используется прокси-объект (PersistentBag, PersistentSet).
LazyCollectionOption.EXTRA:
"Сверхленивая" загрузка: Hibernate загружает только необходимые данные при вызове методов коллекции (например, size(), contains()).
Полезно для больших коллекций, чтобы избежать полной загрузки.
LazyCollectionOption.FALSE:
Коллекция загружается жадно (eager loading), аналогично fetch = FetchType.EAGER.
Не рекомендуется для больших коллекций из-за риска N+1 проблемы.
Жизненный цикл и обработка
Инициализация прокси:
При загрузке родительской сущности коллекция заменяется прокси (реализацией Hibernate).
Прокси перехватывает вызовы методов (например, getItems()) и загружает данные.
Загрузка данных:
Для TRUE: при первом обращении к коллекции выполняется SQL-запрос.
Для EXTRA: методы вроде size() генерируют SELECT COUNT(*), а не загружают все элементы.
Сессия и LazyInitializationException:
Если коллекция запрашивается после закрытия сессии, возникнет исключение (если не используется OpenSessionInView).
Механизмы Hibernate и Spring Boot
Глобальная настройка ленивой загрузки:
Параметр spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true (не рекомендуется, приводит к N+1).
spring.jpa.open-in-view=true (держит сессию открытой до конца HTTP-запроса).
Интеграция с FetchType:
@LazyCollection переопределяет поведение fetch в @OneToMany:
Оптимизация запросов:
Для EXTRA Hibernate использует:
SELECT COUNT(*) FROM orders WHERE user_id = ? — для collection.size().
SELECT id FROM orders WHERE user_id = ? LIMIT 1 — для collection.isEmpty().
Примеры использования
Ленивая загрузка с проверкой размера без загрузки элементов:
Отключение ленивой загрузки (редкий случай):
Ограничения и лучшие практики
N+1 проблема: Даже с LazyCollectionOption.TRUE при обходе коллекции (for (Order o : user.getOrders())) выполняется один запрос для загрузки всех элементов. Решение: @EntityGraph или JOIN FETCH.
EXTRA не поддерживает List.get(index): Для этого требуется полная загрузка.
Тестирование: В тестах с закрытой сессией используйте Hibernate.initialize(collection).
#Java #Training #Hard #Spring #Hibernate #LazyCollection
Аннотация @LazyCollection управляет стратегией ленивой загрузки для коллекций (например, @OneToMany, @ManyToMany) в Hibernate. Определяет, когда и как должны загружаться связанные сущности.
Пакет: org.hibernate.annotations
Применяется к: полям-коллекциям (List, Set, Map и др.) с аннотациями @OneToMany или @ManyToMany.
Параметры и настройки
Аннотация принимает один обязательный параметр — value, который может быть одним из следующих вариантов:
LazyCollectionOption.TRUE (по умолчанию для @OneToMany и @ManyToMany):
Коллекция загружается лениво (при первом обращении).
Используется прокси-объект (PersistentBag, PersistentSet).
LazyCollectionOption.EXTRA:
"Сверхленивая" загрузка: Hibernate загружает только необходимые данные при вызове методов коллекции (например, size(), contains()).
Полезно для больших коллекций, чтобы избежать полной загрузки.
LazyCollectionOption.FALSE:
Коллекция загружается жадно (eager loading), аналогично fetch = FetchType.EAGER.
Не рекомендуется для больших коллекций из-за риска N+1 проблемы.
Жизненный цикл и обработка
Инициализация прокси:
При загрузке родительской сущности коллекция заменяется прокси (реализацией Hibernate).
Прокси перехватывает вызовы методов (например, getItems()) и загружает данные.
Загрузка данных:
Для TRUE: при первом обращении к коллекции выполняется SQL-запрос.
Для EXTRA: методы вроде size() генерируют SELECT COUNT(*), а не загружают все элементы.
Сессия и LazyInitializationException:
Если коллекция запрашивается после закрытия сессии, возникнет исключение (если не используется OpenSessionInView).
Механизмы Hibernate и Spring Boot
Глобальная настройка ленивой загрузки:
Параметр spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true (не рекомендуется, приводит к N+1).
spring.jpa.open-in-view=true (держит сессию открытой до конца HTTP-запроса).
Интеграция с FetchType:
@LazyCollection переопределяет поведение fetch в @OneToMany:
@OneToMany(fetch = FetchType.EAGER) // Игнорируется, если есть @LazyCollection
@LazyCollection(LazyCollectionOption.TRUE)
private List<Order> orders;
Оптимизация запросов:
Для EXTRA Hibernate использует:
SELECT COUNT(*) FROM orders WHERE user_id = ? — для collection.size().
SELECT id FROM orders WHERE user_id = ? LIMIT 1 — для collection.isEmpty().
Примеры использования
Ленивая загрузка с проверкой размера без загрузки элементов:
@OneToMany
@LazyCollection(LazyCollectionOption.EXTRA)
private Set<Comment> comments; // Для comments.size() не загружает все комментарии
Отключение ленивой загрузки (редкий случай):
@OneToMany
@LazyCollection(LazyCollectionOption.FALSE) // Аналог FetchType.EAGER
private List<Post> posts;
Ограничения и лучшие практики
N+1 проблема: Даже с LazyCollectionOption.TRUE при обходе коллекции (for (Order o : user.getOrders())) выполняется один запрос для загрузки всех элементов. Решение: @EntityGraph или JOIN FETCH.
EXTRA не поддерживает List.get(index): Для этого требуется полная загрузка.
Тестирование: В тестах с закрытой сессией используйте Hibernate.initialize(collection).
#Java #Training #Hard #Spring #Hibernate #LazyCollection