问题

JPA的获取策略到底控制了什么?我无法发现渴望和懒惰之间的任何区别。在这两种情况下,JPA / Hibernate都不会自动加入多对一关系。

示例:Person有一个地址。地址可以属于很多人。 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表中进行选择,然后对每个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。

**编辑:**它出现(参见Hibernate FAQherehere),即FetchType不会影响JPA查询。所以在我的情况下,我明确告诉它加入。


#1 热门回答(87 赞)

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

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

SoSELECTJOIN之间存在两个极端和SUBSELECT之间。可以根据她/他的域模型选择合适的策略。

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

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

在Hibernate中。它还允许使用@Fetch(FetchMode.SELECT)明确地设置SELECT模式,这可以通过使用批量大小来调整,例如.@BatchSize(size=10)

EclipseLink中的相应注释是:

@JoinFetch
@BatchFetch

#2 热门回答(42 赞)

"mxc"是正确的.fetchType正好指定750339726时应该解决**的关系。

要通过使用外部联接来优化预先加载,你必须添加

@Fetch(FetchMode.JOIN)

到你的领域。这是一个特定于hibernate的注释。


#3 热门回答(36 赞)

fetchType属性控制在获取主实体时是否立即获取带注释的字段。它不一定决定如何构造fetch语句,实际的sql实现依赖于你使用toplink / hibernate等的提供者。

如果设置为fetchType=EAGER,则表示带注释的字段的值与实体中的其他字段同时填充。因此,如果你打开一个实体管理器来检索你的人物对象然后关闭实体管理器,则随后执行person.address将不会导致抛出延迟加载异常。

如果设置fetchType=LAZY,则仅在访问该字段时填充该字段。如果你已关闭实体管理器,那么如果你执行person.address,则会抛出延迟加载异常。要加载字段,你需要使用em.merge()将实体放回到实体管理器上下文中,然后执行字段访问,然后关闭实体管理器。

在构建具有客户订单集合的客户类时,你可能需要延迟加载。如果你在想要获取客户列表时检索了客户的每个订单,那么当你只查找客户名称和联系详细信息时,这可能是一项昂贵的数据库操作。最好将db访问权限保留到以后。

对于问题的第二部分 - 如何让hibernate生成优化的SQL?

Hibernate应该允许你提供有关如何构建最有效查询的提示,但我怀疑你的表构造有问题。表中是否建立了关系? Hibernate可能已经决定简单的查询比连接更快,特别是如果缺少索引等。


原文链接