Lazy vs Eager fetch
Тема дорожной карты · Spring Boot
Стратегии загрузки JPA определяют, когда Hibernate загружает связанные сущности относительно владеющей — либо немедленно вместе с ней (жадная загрузка), либо при первом обращении (ленивая загрузка) — напрямую влияя на количество выполняемых SQL-запросов и производительность Spring Boot-приложения. FetchType.LAZY (умолчание для @OneToMany и @ManyToMany) откладывает загрузку коллекции до вызова геттера внутри активной сессии Hibernate; обращение к ней вне сессии вызывает LazyInitializationException — распространённую ошибку в Spring Boot-приложениях, не использующих паттерн Open Session in View. FetchType.EAGER (умолчание для @ManyToOne и @OneToOne) загружает связанную сущность вместе с родителем через JOIN, что может вызвать проблему N+1 запросов при загрузке списка родителей с жадно загружаемыми детьми — обнаруживаемую через spring.jpa.show-sql=true и статистику Hibernate. Рекомендуемый подход к стратегиям загрузки JPA в Spring Boot — оставлять ассоциации ленивыми и использовать явный JOIN FETCH в JPQL-запросах с @Query или аннотацию @EntityGraph в Spring Data JPA для жадной загрузки только там, где это требуется по бизнес-логике. Профилирование и настройка стратегий загрузки с помощью инструментов вроде StatisticsImpl Hibernate, метрик Spring Boot Actuator или Datasource Proxy обязательны для высоконагруженных Spring Boot-приложений на PostgreSQL или MySQL.
Как это работает
Lazy vs Eager fetch: Spring Data JPA оборачивает Hibernate (JPA-реализация). @Entity маппит Java-класс → DB-таблица; JpaRepository<T, ID> даёт CRUD + paging + sorting бесплатно. Method names типа findByEmailAndStatus парсятся в queries; сложные queries — @Query (JPQL или native SQL). Relations: @OneToMany, @ManyToOne, @ManyToMany — дефолтный fetch LAZY (one-to-many) или EAGER (many-to-one); знаменитая N+1 проблема прячется здесь. @Transactional оборачивает service-методы в DB-транзакцию.
Когда применять
Все relations LAZY по дефолту + JOIN FETCH или entity graphs для eager-загрузки только когда надо. Projections (DTO/interface) для read-only endpoints — пропускают Hibernate entity overhead. Мониторьте N+1 (Hibernate stats, p6spy или Datasource Proxy в тестах). Для heavy-read — raw JdbcTemplate или jOOQ — JPA отличен для CRUD, хуже для сложной аналитики.
Типичные ошибки
Ловушки Lazy vs Eager fetch: N+1 queries (lazy loading в цикле); EAGER на каждом relation (огромные cascading joins); @Transactional на private/self-invocation (proxy не intercept-ит — аннотация ничего не делает); auto-DDL (spring.jpa.hibernate.ddl-auto=update) в prod (тихий + опасный schema drift).