Эффективная выборка дочерних / родительских объектов в двунаправленном отношении «многие ко многим» - PullRequest
0 голосов
/ 01 октября 2018

Я занимаюсь разработкой службы SpringBoot, которая использует базу данных mysql.

В моей базе данных есть три таблицы: Person, Recipient и Category.Person имеет двунаправленное отношение «многие ко многим» с Category, так же как и Recipient.Коллекции загружаются лениво.

В контроллере я хочу дать обзор сущностей в этих трех таблицах.Мой код на уровне сервиса выглядит так:

List<Person> allPersons = personRepository.findAll();
List<Recipient> allRecipients = recipientRepository.findAll();
List<Category> allCategories = categoryRepository.findAll();

for(Person person : allPersons){
    Set<Category> categories = person.getCategories();
    for(Category category : categories){
        // do something with the person and the categories
    }
}

for(Recipient recipient : allRecipients){
    Set<Category> categories = recipient.getCategories();
    for(Category category : categories){
        // do something with the recipient and the categories
    }
}

for(Category category : allCategories){
    Set<Person> persons = category.getPersons();
    for(Person person : persons){
        // do something with the category and the persons
    }
    Set<Recipient> recipients = category.getRecipients();
    for(Recipient recipient : recipients){
        // do something with the category and the recipients
    }
}

В первых трех строках все необходимые объекты загружаются из базы данных ровно один раз в течение трех запросов к базе данных.Это нормально с точки зрения производительности.Но:

Согласно журналам, при вызове, например,

Set<Category> categories = person.getCategories()

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

Например, если в базе данных 5 человек, 6 получателей и 7 категорий, служба выполняет в общей сложности 3 + 5 + 6 + 2 * 7 = 28 запросов к базе данных.,Очевидно, что это очень неэффективно.

Мой вопрос:

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

1 Ответ

0 голосов
/ 01 октября 2018

Проблема, с которой вы сталкиваетесь, является типичной проблемой спящего режима N + 1. Вы можете быстро получить свою коллекцию и написать собственный запрос.

@Query("Select p from Person p join fetch p.categories categories)
public List<Person> fetchAllPerson();

Подробнее об этом можно прочитать JPA Hibernate n +1 выпуск (Lazy & Eager Diff)

...