JPA 急切获取未加入

2022-08-31 08:47:41

JPA的抓取策略究竟控制着什么?我看不出急切和懒惰之间有什么区别。在这两种情况下,JPA/休眠都不会自动加入多对一关系。

示例:人员只有一个地址。一个地址可以属于许多人。JPA 注释的实体类如下所示:

@Entity
public class Person {
    @Id
    public Integer id;

    public String name;

    @ManyToOne(fetch=FetchType.LAZY or EAGER)
    public Address address;
}

@Entity
public class Address {
    @Id
    public Integer id;

    public String name;
}

如果我使用 JPA 查询:

select p from Person p where ...

JPA/Hibernate 生成一个 SQL 查询以从 Person 表中进行选择,然后为每个人生成一个不同的地址查询:

select ... from Person where ...
select ... from Address where id=1
select ... from Address where id=2
select ... from Address where id=3

这对于大型结果集非常不利。如果有 1000 人,则会生成 1001 个查询(1 个来自 Person,1000 个与 Address 不同)。我知道这一点,因为我正在查看MySQL的查询日志。我的理解是,将地址的提取类型设置为 eager 将导致 JPA/Hibernate 自动查询连接。但是,无论提取类型如何,它仍然会为关系生成不同的查询。

只有当我明确告诉它加入时,它才真正加入:

select p, a from Person p left join p.address a where ...

我在这里错过了什么吗?我现在必须为每个查询手动编写代码,以便它左连接多对一关系。我正在将Hibernate的JPA实现与MySQL一起使用。

编辑:它似乎(请参阅此处此处的休眠常见问题解答)不会影响 JPA 查询。因此,就我而言,我已经明确告诉它加入。FetchType


答案 1

JPA 没有提供任何关于映射注释以选择获取策略的规范。通常,可以通过以下任何一种方式获取相关实体

  • SELECT = >一个根实体查询 + 一个查询每个根实体的相关映射实体/集合 = (n+1) 查询
  • SUBSELECT = >一个查询的根实体 + 第二个查询第二个查询第一个查询中检索到的所有根实体的相关映射实体/集合 = 2 个查询
  • JOIN =>一个查询来获取根实体及其所有映射的实体/集合 = 1 个查询

因此,这是两个极端,介于两者之间。人们可以根据她/他的领域模型选择合适的策略。SELECTJOINSUBSELECT

默认情况下,JPA/EclipseLink 和 Hibernate 都使用。这可以通过以下方式覆盖:SELECT

@Fetch(FetchMode.JOIN) 
@Fetch(FetchMode.SUBSELECT)

在冬眠中。它还允许显式设置模式,可以使用批量大小进行调整,例如。SELECT@Fetch(FetchMode.SELECT)@BatchSize(size=10)

EclipseLink 中相应的注释是:

@JoinFetch
@BatchFetch

答案 2

“mxc”是对的。 只是指定何时应解析关系。fetchType

要通过使用外连接来优化预先加载,您必须添加

@Fetch(FetchMode.JOIN)

到你的领域。这是一个休眠特定的注释。


推荐