当前位置: 首页 > 知识库问答 >
问题:

即使在使用@Fetch(FetchMode.JOIN)时,JPA Hibernate也会出现太多查询问题

壤驷俊逸
2023-03-14

我正在使用spring boot开发REST应用程序,并试图优化查询的性能。我目前正在使用存储库中的findAll,这会导致性能问题。代码如下:

个人实体

@Entity
@Table(name = "cd_person")
@Data
@NoArgsConstructor
public class Person {
    ....
    @OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @JoinColumn(name = "password_id")
    @Fetch(FetchMode.JOIN)
    private Password password;
    ....
    @ManyToMany(fetch = FetchType.EAGER, cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH})
    @JoinTable(name = "cd_person_role",
        joinColumns = @JoinColumn(name = "person_id", referencedColumnName = "id"),
        inverseJoinColumns = @JoinColumn(name = "role_id", referencedColumnName = "id"))
    @Fetch(FetchMode.JOIN)
    private Set<Role> roles = new HashSet<>();
}

密码实体

@Entity
@Table(name = "cd_password")
@Data
@NoArgsConstructor
public class Password {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id", updatable = false, nullable = false)
    private Long id;

    @Column(name = "password_hash", nullable = false)
    private String passwordHash;
    .......
}

角色实体

@Entity
@Table(name = "cd_role")
@Data
@NoArgsConstructor
public class Role {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "role_type")
    @Enumerated(EnumType.STRING)
    private RoleType roleType;
    ....
}

人员存储库

public interface PersonRepository extends CrudRepository<Person, Long> {

    Optional<Person> findByEmail(String email);

}

当我做一个人epository.findAll()时,在人表中的每一行都会触发选择查询,以获取密码和角色。我知道我可以在存储库中使用@Query注释和JOIN FETCH来强制生成单个查询,但是我想知道是否有其他方法可以这样做。我正在寻找我们可以在实体级别上做的事情来减少查询。

使用Spring Boot2.1.5-RELEASE版本和相关依赖项。

附言。@Data@NoArgsConstructor是Lombok注释。

共有3个答案

张砚
2023-03-14

对您的问题的不满意的回答是:不,没有办法注释/配置实体,以便抓取模式也适用于查询。

正如您正确发现的那样,您可以操作查询本身。除此之外,还可以使用Hibernate的读取配置文件或利用JPA实体图——但所有这些都需要在查询/会话级别进行编程干预。

师向文
2023-03-14

我会让实体保持原样,并用@Query注释覆盖存储库中的findAll方法。这样,代码重构是最小的(只有一个存储库更改,而不是实体更改)。

通安宁
2023-03-14

最简单的代码更改是使用spring数据中的ad-hoc EntityGraph特性。只需覆盖PersonRepository的findAll(),并使用@EntityGraph来配置图形。此图中的所有实体都将被提取到一起。

public interface PersonRepository extends CrudRepository<Person, Long> {

    @EntityGraph(attributePaths = { "password", "roles" })
    public List<Person> findAll();

}

在幕后,它的工作原理类似于JOIN FETCH。将只生成具有左联接的单个SQL。

 类似资料:
  • 考虑和<代码>雇员< /代码>和<代码>地址< /代码>关系。在和之间有一对一的映射。以下是模型: 现在,当我执行以下HQL查询时,它会在内部生成两个查询。一个取员工,另一个取地址。 由Hibernate生成的SQL查询 因为我使用的是,所以我希望Hibernate只执行一个带有JOIN的查询,一次性获取员工和地址数据。 你知道为什么它要执行两个查询吗?我如何让Hibernate使用join只执行

  • 和我的持久性类: 我不明白问题出在哪里?

  • 我希望在一个select请求中运行以下查询: 问题是所有内容都是由单独的多个查询获取的。我只希望团队和团队的球员和每个球员的技能在一个请求中被获取。但是相反,我有多个选择查询来获取每个团队、玩家、每个玩家的统计数据和技能。 以下是与注释一起使用的实体: 游戏实体: 团队实体: 玩家实体: 你能指出所犯的错误吗?我需要一个选择查询来加载游戏,它是团队、团队的球员和每个球员的技能。 编辑1:以下是po

  • 我正在尝试使用连接获取运行查询,但我也在使用DTO投影来提高性能,但我得到了以下异常: org.hibernate.QueryException:查询指定的联接获取,但获取的关联的所有者不存在于选择列表中[FromElement{显式,不是集合联接,获取联接,获取非惰性属性,类Alias=pi,角色=returnitRest。Ereturn.productItems, tableName=prod

  • 是我的服务方式 } 2018-10-04 17:15:44.452 WARN 64056---[nio-8080-exec-4]O.s.web.servlet.PageNotFound:不支持请求方法“Post”2018-10-04 17:15:44.452 WARN 64056---[nio-8080-exec-4].w.s.m.s.DefaultHandlerExceptionResolver

  • 你会得到一本电话簿,里面有人们的名字和电话号码。之后,你会得到一些人的名字作为查询。对于每个查询,打印该人的电话号码。 输入格式 第一行有一个整数,表示通讯录中的条目数。每个条目由两行组成:姓名和相应的电话号码。 在这些之后,将会有一些查询。每个查询将包含一个人的姓名。读取查询直到文件结束。 限制条件:一个人的姓名仅由小写英文字母组成,可能采用“名字姓氏”格式,也可能采用“名字”格式。每个电话号码