JPA渴望获取不加入 [英] JPA eager fetch does not join

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

问题描述

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



例如:Person有一个地址。一个地址可以属于很多人。 JPA批注的实体类看起来像:

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

公共字符串名称;

@ManyToOne(fetch = FetchType.LAZY或EAGER)
公共地址;
}

@Entity
公共类地址{
@Id
public Integer id;

公共字符串名称;
}

如果我使用JPA查询:

 从Person p选择p 



JPA / Hibernate生成一个SQL查询来从Person表中选择,然后为每个人个人显式地址查询:

  select ... from Person where ... 
select ... from地址where id = 1
select ... from地址id = 2
select ...来自地址,其中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 FAQ 这里这里), FetchType 不影响JPA查询。所以在我的情况下,我明确地告诉它加入。

解决方案

JPA不提供任何映射注释来选择获取战略。一般来说,相关实体可以通过以下任何一种方式获取


  • SELECT =>一个查询根实体+一个查询相关映射实体/每个根实体的集合=(n + 1)个查询

  • SUBSELECT =>根实体的一个查询+相关映射实体的第二个查询/第一个查询= 2个查询

  • JOIN =>一个查询以获取根实体及其所有映射实体/集合= 1个查询



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



默认情况下, SELECT EclipseLink和Hibernate。这可以通过使用以下来覆盖:

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

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



EclipseLink中的相应注释是:

  @JoinFetch 
@BatchFetch


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.

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;
}

If I use the JPA query:

select p from Person p where ...

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

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 ...

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.

Edit: 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 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 => one query for root entities + one query for related mapped entity/collection of each root entity = (n+1) queries
  • SUBSELECT => one query for root entities + second query for related mapped entity/collection of all root entities retrieved in first query = 2 queries
  • JOIN => one query to fetch both root entities and all of their mapped entity/collection = 1 query

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

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

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

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).

Corresponding annotations in EclipseLink are:

@JoinFetch
@BatchFetch

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

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