JPA 急切获取不加入 [英] JPA eager fetch does not join

查看:24
本文介绍了JPA 急切获取不加入的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

JPA 的 fetch 策略究竟控制什么?我无法检测到渴望和懒惰之间的任何区别.在这两种情况下,JPA/Hibernate 都不会自动加入多对一关系.

What exactly does JPA's fetch strategy control? I can't detect any difference between eager and lazy. In both cases JPA/Hibernate does not automatically join many-to-one relationships.

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

Example: Person has a single address. An address can belong to many people. The JPA annotated entity classes look like:

@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 查询:

If I use the JPA query:

select p from Person p where ...

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

JPA/Hibernate generates one SQL query to select from Person table, and then a distinct address query for each 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 使用连接自动查询.但是,无论提取类型如何,它仍然会为关系生成不同的查询.

This is very bad for large result sets. If there are 1000 people it generates 1001 queries (1 from Person and 1000 distinct from Address). I know this because I'm looking at MySQL's query log. It was my understanding that setting address's fetch type to eager will cause JPA/Hibernate to automatically query with a join. However, regardless of the fetch type, it still generates distinct queries for relationships.

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

Only when I explicitly tell it to join does it actually join:

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

我在这里遗漏了什么吗?我现在必须手动编码每个查询,以便它离开加入多对一关系.我在 MySQL 中使用 Hibernate 的 JPA 实现.

Am I missing something here? I now have to hand code every query so that it left joins the many-to-one relationships. I'm using Hibernate's JPA implementation with MySQL.

它出现了(参见 Hibernate FAQ 这里此处)FetchType 不会影响 JPA 查询.所以就我而言,我已经明确告诉它加入.

It appears (see Hibernate FAQ here and here) that FetchType does not impact JPA queries. So in my case I have explicitly tell it to join.

推荐答案

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

JPA doesn't provide any specification on mapping annotations to select fetch strategy. In general, related entities can be fetched in any one of the ways given below

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

所以 SELECTJOIN 是两个极端,SUBSELECT 介于两者之间.可以根据她/他的领域模型选择合适的策略.

So SELECT and JOIN are two extremes and SUBSELECT falls in between. One can choose suitable strategy based on her/his domain model.

默认情况下 SELECT 被 JPA/EclipseLink 和 Hibernate 使用.这可以使用以下方法覆盖:

By default SELECT is used by both JPA/EclipseLink and Hibernate. This can be overridden by using:

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

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

in Hibernate. It also allows to set SELECT mode explicitly using @Fetch(FetchMode.SELECT) which can be tuned by using batch size e.g. @BatchSize(size=10).

EclipseLink中对应的注解为:

Corresponding annotations in EclipseLink are:

@JoinFetch
@BatchFetch

这篇关于JPA 急切获取不加入的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆