Hibernate中JOIN和JOIN FETCH之间的区别

时间:2013-07-02 16:50:38

标签: java hibernate join hql fetch

请帮助我了解使用常规JOIN的位置以及JOIN FETCH的位置。

例如,如果我们有这两个查询

FROM Employee emp
JOIN emp.department dep

FROM Employee emp
JOIN FETCH emp.department dep

它们之间有什么区别吗?如果是的话,哪一个使用?

5 个答案:

答案 0 :(得分:139)

在这两个查询中,您使用JOIN查询至少有一个部门关联的所有员工。

但是,区别在于:在第一个查询中,您只返回Hibernate的Employes。在第二个查询中,您将返回Employes 关联的所有Departments。

因此,如果您使用第二个查询,则无需再次执行新查询来查看数据库以查看每个员工的部门。

如果您确定需要每个员工的部门,则可以使用第二个查询。如果您不需要该部门,请使用第一个查询。

如果您需要应用某些WHERE条件(您可能需要的话),我建议您阅读此链接:How to properly express JPQL "join fetch" with "where" clause as JPA 2 CriteriaQuery?

<强>更新

如果您不使用fetch并继续返回部门,那是因为您在Employee和部门(@OneToMany)之间的映射设置为FetchType.EAGER。在这种情况下,任何带有fetch的HQL(FROM Employee或不带{}}查询都会带来所有部门。请注意,默认情况下,所有映射* ToOne(@ManyToOne@OneToOne)都是EAGER。

答案 1 :(得分:55)

在我之前提到的this link评论中,请阅读此部分:

  

“fetch”连接允许值的关联或集合   使用单个选择与其父对象一起初始化。   这在集合的情况下特别有用。的它   有效地覆盖了外连接和延迟声明   关联和集合的映射文件

如果您对实体内部的集合(fetchType.LAZY)具有(fetch = FetchType.LAZY)属性,那么这个“JOIN FETCH”将会产生效果。

它只会影响“查询应该发生时”的方法。你还必须知道this

  

hibernate有两个正交的概念:何时获取关联以及如何获取   它取了。重要的是你不要混淆它们。我们用   获取调整性能。我们可以使用懒惰来定义合同   什么数据始终可用于特定的任何分离实例   类。

何时获取关联 - &gt;你的“FETCH”类型

如何获取 - &gt;加入/选择/子选择/批次

在您的情况下,如果您将部门作为Employee中的集合,FETCH将只有它的效果,在实体中是这样的:

@OneToMany(fetch = FetchType.LAZY)
private Set<Department> department;

使用时

FROM Employee emp
JOIN FETCH emp.department dep

您将获得empemp.dep。当你没有使用fetch时,你仍然可以得到emp.dep但是hibernate会处理另一个选择到数据库以获得那组部门。

所以它只是性能调优的问题,关于你想要在一个查询中获得所有结果(你需要或不需要)(或者你需要它),或者你想在需要时查询它(延迟提取)

当您需要使用一个选择(一个大查询)获取小数据时,请使用急切提取。或者使用延迟提取来查询您需要的内容(许多较小的查询)。

在以下时间使用fetch:

  • 在您即将获得的实体中没有大的不需要的收集/设置

  • 从应用程序服务器到数据库服务器的通信太远并且需要很长时间

  • 当您无法访问该集合时,您可能需要该集合(事务性方法/类

    < / LI>

答案 2 :(得分:4)

如果您将@oneToOne映射设置为FetchType.LAZY并且您使用第二个查询(因为您需要将Department对象作为Employee对象的一部分加载)Hibernate将要做的是,它将发出查询以获取每个部门的对象它从DB获取的单个Employee对象。稍后在代码中,您可以通过Employee到Department单值关联访问Department对象,Hibernate不会发出任何查询来获取给定Employee的Department对象。记住,Hibernate仍会发出与其获取的Employees数量相等的查询。如果您希望访问所有Employee对象的Department对象

,Hibernate将在上述两个查询中发出相同数量的查询

答案 3 :(得分:2)

Dherik:我不确定你说的是什么,当你不使用fetch时,结果的类型为:List<Object[ ]>,这意味着一个Object表列表,而不是一个列表雇员。

Object[0] refers an Employee entity 
Object[1] refers a Departement entity 

当您使用fetch时,只有一个select,结果是包含部分列表的Employee List<Employee>列表。它会覆盖实体的惰性声明。

答案 4 :(得分:1)

加入

针对实体关联使用JOIN时,JPA将在生成的SQL语句中的父实体表和子实体表之间生成JOIN。

因此,以您的示例为例,在执行此JPQL查询时:

FROM Employee emp
JOIN emp.department dep

Hibernate将生成以下SQL语句:

SELECT emp.*
FROM employee emp
JOIN department dep ON emp.department_id = dep.id
  

请注意,SQL SELECT子句仅包含employee表列,而不包含department列。要获取department表列,我们需要使用JOIN FETCH而不是JOIN

加入比赛

因此,与JOIN相比,JOIN FETCH允许您将联接表列投影到生成的SQL语句的SELECT子句中。

因此,在您的示例中,执行此JPQL查询时:

FROM Employee emp
JOIN FETCH emp.department dep

Hibernate将生成以下SQL语句:

SELECT emp.*, dept.*
FROM employee emp
JOIN department dep ON emp.department_id = dep.id
  

请注意,这次也选择了department表列,而不仅仅是与FROM JPQL子句中列出的实体相关联的列。

此外,JOIN FETCH是使用Hibernate时解决LazyInitializationException的好方法,因为您可以使用FetchType.LAZY提取策略以及要提取的主要实体来初始化实体关联。 / p>