Использование данных Spring JPA EntityGraph с режимом загрузки LAZY для поля NamedAttributeNode - PullRequest
0 голосов
/ 07 февраля 2020

Я сталкиваюсь с 2 проблемами: N + 1 запрос и Недостаточно памяти (OOM).

Я решил OOM путем подкачки и отложенной загрузки:

@OneToMany(fetch = FetchType.LAZY)
@JoinColumn(name = "department_id")
private Set<Employee> employees;

Но когда я использую отложенная загрузка, N + 1 запрос произошел. Поэтому я стараюсь использовать EntityGraph как https://www.baeldung.com/spring-data-jpa-named-entity-graphs. Но, как показывают мои исследования и локальные тесты, EntityGraph всегда активно загружает поле NamedAttributeNode - поле ассоциации, которое я хочу загружать лениво - сначала не загружайте все данные:

@Entity
@Table(name = "department")
@NamedEntityGraph(name = "Department",
        attributeNodes = {
                @NamedAttributeNode("employees")
        }
)
public class Department implements Serializable {
    @OneToMany(fetch = FetchType.LAZY)
    @JoinColumn(name = "department_id")
    private Set<Employee> employees;
}

Итак есть ли способ получить их обоих? Используйте EntityGraph, чтобы избежать N + 1 и ленивая загрузка, чтобы избежать OOM?

ОБНОВЛЕНИЕ: Может ли EntityGraph эффективно работать с Pageable эффективно? Я имею в виду не загружать все данные в запросе JOIN.

1 Ответ

1 голос
/ 07 февраля 2020

При использовании EntityGraph все ваши NamedAttributeNode ассоциации будут загружены в 1 запрос с предложением Join. Включите журнал sql, чтобы увидеть, сколько запросов hibernate выполняет для загрузки объектов в различных сценариях ios

logging.level.org.hibernate.SQL=DEBUG

. Вы увидите, что при использовании @OneToMany(fetch = FetchType.EAGER) без EntityGraph загружаются сотрудники в отдельных select запросов (N + 1), но с использованием EntityGraph он выполняет только 1 select ... join

Также не забудьте указать имя графа сущностей в репозитории, например:

@EntityGraph(value = "Department")
List<Department> findAll();

ОБНОВЛЕНИЕ: Spring DATA Pagination не работает на стороне базы данных. Он будет получать все данные и затем фильтроваться в памяти. Вот как это работает .. Есть несколько обходных путей, проверьте следующие ссылки:

Как можно избежать предупреждения "firstResult / maxResults, указанных при получении коллекции; применение в памяти!" при использовании Hibernate?

Избегание "HHH000104: firstResult / maxResults, указанных при получении коллекции; применение в памяти!" Использование Spring Data

Блог VladMihalcea Лучший способ исправить Hibernate HHH000104

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

...