java - 在双向多对多关系中有效获取子/父实体

标签 java mysql spring-boot many-to-many lazy-loading

我正在开发一个使用 mysql 数据库的 SpringBoot 服务。

我的数据库中有三个表:人员、收件人和类别。 Person 与 Category 具有双向多对多关系,Recipient 也是如此。集合是延迟加载的。

在 Controller 中,我想概述这三个表中的实体。我在服务层的代码如下所示:

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 次数据库查询。显然,这是非常低效的。

我的问题是:

我需要更改什么才能使服务仅使用尽可能少的数据库查询来获取每个实体一次?

最佳答案

您面临的问题是典型的 hibernate N+1问题。您可以急切地获取您的集合并编写自己的查询。

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

您可以阅读更多相关信息 JPA Hibernate n+1 issue (Lazy & Eager Diff)

关于java - 在双向多对多关系中有效获取子/父实体,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52591086/

相关文章:

mysql - 在 mySQL 中平均子查询的结果

java - 在 java 中显式提供向上转换

java - 如何将文档监听器添加到 JScrollPane 内的 JTextArea?

mysql - mysqldump 上的查询

java - NullPointerException : ProGuard, Spring 启动

spring-boot - Spring Boot 应用程序中的 Tesseract 为日语提供了无意义的结果

Java Spring Boot 登录

java - 静态方法什么都不返回? (试图返回一个 tostring)

java - 如何处理 cxf/camel 生产者模板中的关闭/不可用端点

mysql - 查找给定位置(经度、纬度)Y 半径范围内 X 的所有值