请帮助我了解使用常规JOIN的位置以及JOIN FETCH的位置。
例如,如果我们有这两个查询
FROM Employee emp
JOIN emp.department dep
和
FROM Employee emp
JOIN FETCH emp.department dep
它们之间有什么区别吗?如果是的话,哪一个使用?
答案 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
您将获得emp
和emp.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>