【问题标题】:How to solve n + 1 problem in hibernate for my case?如何在我的情况下解决休眠中的 n + 1 问题?
【发布时间】:2021-07-29 23:22:27
【问题描述】:

我在休眠时遇到了 n + 1 选择问题。我看了很多关于这个主题的文章,但我不明白我的错误是什么。

我的查询:

public interface ClientRepository extends JpaRepository<Client, UUID> {
 @Query("SELECT c from Client c LEFT JOIN Subscription s on c.company.id = s.company.id WHERE s.id LIKE '%trial%' order by c.firstName ASC")  
 List<Client> getAllTrials();
}

订阅实体:

       @Entity
        public class Subscription implements Serializable {
          @Id
          private String id;
       
          @ManyToOne(fetch = FetchType.LAZY)
          @JoinColumn
          private Company company;
      
          @NotNull
          private OffsetDateTime time;
          
          @NotNull
          private SubscriptionStatus status;
     //getters and setters + constructors = ...

客户实体:

    @Entity
    public class Client implements Serializable {
      @Id
      @GeneratedValue
      private UUID id;
    
      @ManyToOne(fetch = FetchType.LAZY)
      @JoinColumn
      private Company company;
    
      @NotBlank
      private String firstName;
    
      @NotBlank
      private String lastName;
    
      @NotBlank
      private String email;

...

公司实体:

    @Entity
    public class Company implements Serializable {
      @Id
      @GeneratedValue
      private UUID id;
    
      @OneToMany(mappedBy = "company", fetch = FetchType.LAZY, cascade = CascadeType.REMOVE)
      @JsonIgnoreProperties("company")
      private List<Client> clients;
    
      @OneToMany(mappedBy = "company", fetch = FetchType.LAZY, cascade = CascadeType.REMOVE)
      private List<Subscription> subscriptions = new ArrayList<>();

...

当我尝试获取这些属性时,hibernate 使用了太多查询。

 model.addAttribute ("trialUsers", clientService.getAllTrialClients ());
 
<table>
      <thead>
      <tr>
        <td>Name</td>
        <td>Surname</td>
        <td>Email</td>
        <td>time</td>
        <td>id</td>
        <td>status</td>
      </tr>
      </thead>
      <tbody>
      <tr th:each="client : ${trialUsers}">
        <td th:text="${client.firstName}"></td>
        <td th:text="${client.lastName}"></td>
        <td th:text="${client.email}"></td>
        <td th:text="${client.company.subscriptions[0].time}"></td>
        <td th:text="${client.company.subscriptions[0].id}"></td>
        <td th:text="${client.company.subscriptions[0].status}"></td>
      </tr>
      </tbody>
    </table>

【问题讨论】:

标签: java sql hibernate jpa thymeleaf


【解决方案1】:

@NamedEntityGraph 会解决你的问题。

您需要创建NamedEntityGraph,如下所示。

@NamedEntityGraph(name = "graph.ClientAndCompany", attributeNodes = {
        @NamedAttributeNode(value = "company") })

您可以在 Client Entity 上使用定义它

@NamedEntityGraph(name = "graph.ClientAndCompany", attributeNodes = {
        @NamedAttributeNode(value = "company") })
@Entity
public class Client implements Serializable {
      @Id
      @GeneratedValue
      private UUID id;
    
      @ManyToOne(fetch = FetchType.LAZY)
      @JoinColumn
      private Company company;
    
      @NotBlank
      private String firstName;
    
      @NotBlank
      private String lastName;
    
      @NotBlank
      private String email;

...

然后你需要在你的存储库方法中使用它

public interface ClientRepository extends JpaRepository<Client, UUID> {

 @EntityGraph(value = "graph.ClientAndCompany", type = EntityGraphType.FETCH)
 @Query("SELECT c from Client c LEFT JOIN Subscription s on c.company.id = s.company.id WHERE s.id LIKE '%trial%' order by c.firstName ASC")  
 List<Client> getAllTrials();

}

您可以找到更多详情here

【讨论】:

  • 感谢您的解决方案。有趣的文章。但由于某种原因,这对我不起作用。
【解决方案2】:

也许这不是一个很好的解决方案,但现在我有 4 个选择而不是 n+1。

 @Query("from Subscription s where s.id like '%trial%'")
  List<Subscription> findAllSubTrial();

@Query("SELECT c from Client c LEFT JOIN Subscription s on c.company.id = s.company.id WHERE s.id LIKE '%trial%' order by c.firstName ASC")
  List<Client> getAllTrials();

model.addAttribute ("clients", clientService.getAllTrialClients ());
model.addAttribute("subscriptions", subscriptionService.findAllSubTrial ());
model.addAttribute("standardDate", new Date());

<table>
          <thead>
          <tr>
          <td>Name</td>
          <td>last name</td>
          <td>Email</td>
          <td>time</td>
          <td>extend period</td>
          </tr>
          </thead>
          <tbody>
          <tr role="row" th:each="client:${clients}">
            <td th:text="${client.firstName}">
            <td th:text="${client.lastName}">
            <td th:text="${client.email}">
            <td>
              <input type="date" th:each="subscription : ${subscriptions}"
                 th:if="(${subscription.company.id} == ${client.company.id})"
                 th:value="${#temporals.format(subscription.time, 'yyyy-MM-dd')}"
                 th:min="${#temporals.format(subscription.time, 'yyyy-MM-dd')}"
                     th:id='${subscription.id}'>
            <td>
      
            </td>
          </tr>
          </tbody>
        </table>

【讨论】:

    猜你喜欢
    • 2021-04-26
    • 1970-01-01
    • 2019-12-15
    • 1970-01-01
    • 2011-03-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-27
    相关资源
    最近更新 更多