abb*_*bas 158 java hibernate join hql fetch
请帮助我了解在哪里使用常规JOIN以及JOIN FETCH的位置.
例如,如果我们有这两个查询
FROM Employee emp
JOIN emp.department dep
Run Code Online (Sandbox Code Playgroud)
和
FROM Employee emp
JOIN FETCH emp.department dep
Run Code Online (Sandbox Code Playgroud)
它们之间有什么区别吗?如果是的话,哪一个使用的时候?
Dhe*_*rik 162
在这两个查询中,您使用JOIN查询至少有一个部门关联的所有员工.
但是,区别在于:在第一个查询中,您只返回Hibernate的Employes.在第二个查询中,您将返回Employes 和所有Departments关联.
因此,如果您使用第二个查询,则无需再次执行新查询来查看数据库以查看每个Employee的Departments.
当您确定需要每个员工的部门时,可以使用第二个查询.如果您不需要该部门,请使用第一个查询.
如果你需要应用一些WHERE条件(你可能需要什么),我建议阅读这个链接:如何正确表达JPQL"join fetch"和"where"子句作为JPA 2 CriteriaQuery?
更新
如果您不使用fetch并且继续返回Departments,那是因为您在Employee和Department(a @OneToMany)之间的映射设置为FetchType.EAGER.在这种情况下,任何HQL(有fetch或没有)查询FROM Employee将带来所有部门.请记住,默认情况下,所有映射*ToOne(@ManyToOne和@OneToOne)都是EAGER.
Ang*_*gga 58
在我之前提到的评论链接中,请阅读此部分:
"fetch"连接允许使用单个select来初始化值的关联或集合及其父对象.这在集合的情况下特别有用.它有效地覆盖了关联和集合的映射文件的外连接和延迟声明.
如果你在实体内部有一个集合的(fetch = FetchType.LAZY)属性,那么这个"JOIN FETCH"会产生影响(例如波纹管).
它只会影响"何时应该发生查询"的方法.你也必须知道这个:
hibernate有两个正交的概念:何时获取关联以及如何获取它.重要的是你不要混淆它们.我们使用fetch来调整性能.我们可以使用lazy来定义在特定类的任何分离实例中始终可用的数据的契约.
何时获取关联 - >您的"FETCH"类型
如何获取 - >加入/选择/子选择/批量
在您的情况下,如果您将部门作为Employee中的集合,FETCH将只有它的效果,在实体中是这样的:
@OneToMany(fetch = FetchType.LAZY)
private Set<Department> department;
Run Code Online (Sandbox Code Playgroud)
当你使用
FROM Employee emp
JOIN FETCH emp.department dep
Run Code Online (Sandbox Code Playgroud)
你会得到emp和emp.dep.当你没有使用fetch时你仍然可以得到emp.dep但是hibernate将处理另一个select到数据库以获得那组部门.
所以它只是性能调优的问题,你想要得到的所有结果(你需要与否)在单个查询(预先抓取),或要查询其后者,当你需要它(延迟抓取).
当您需要使用一个选择(一个大查询)获取小数据时,请使用急切提取.或者使用延迟提取来查询您需要的内容(许多较小的查询).
使用fetch时:
你要获得的实体内没有大量不需要的收集/设置
从应用服务器到数据库服务器的通信太远,需要很长时间
当您无法访问它时(在事务方法/类之外),您可能需要该集合
Vla*_*cea 52
当JOIN针对实体关联使用时,JPA 将在生成的 SQL 语句中的父实体和子实体表之间生成一个 JOIN。
因此,以您为例,在执行此 JPQL 查询时:
FROM Employee emp
JOIN emp.department dep
Run Code Online (Sandbox Code Playgroud)
Hibernate 将生成以下 SQL 语句:
SELECT emp.*
FROM employee emp
JOIN department dep ON emp.department_id = dep.id
Run Code Online (Sandbox Code Playgroud)
请注意,SQL
SELECT子句仅包含employee表列,而不包含表列department。要获取department表列,我们需要使用JOIN FETCH代替JOIN。
因此,与 相比JOIN,JOIN FETCH允许您SELECT在生成的 SQL 语句的子句中投影连接表列。
因此,在您的示例中,在执行此 JPQL 查询时:
FROM Employee emp
JOIN FETCH emp.department dep
Run Code Online (Sandbox Code Playgroud)
Hibernate 将生成以下 SQL 语句:
SELECT emp.*, dept.*
FROM employee emp
JOIN department dep ON emp.department_id = dep.id
Run Code Online (Sandbox Code Playgroud)
请注意,这次
department还选择了表列,而不仅仅是与FROMJPQL 子句中列出的实体关联的列。
此外,这JOIN FETCH是解决LazyInitializationException使用 Hibernate 时的好方法,因为您可以使用FetchType.LAZY获取策略以及您正在获取的主要实体来初始化实体关联。
TLDR:关键字FETCH告诉实体管理器也获取急切加入的关联实体(当情况还不是这样时)。
假设我们有一个用户实体和 userInfo 实体。用户实体@OneToMany与userInfo的关系如下:
import javax.persistence.*;
@Entity
@Table(name= "test_user")
public class User {
// ... user properties id etc
@OneToMany(mappedBy = "user" fetch = FetchType.LAZY)
private List<UserInfo> infoList;
}
Run Code Online (Sandbox Code Playgroud)
假设我们有以下查询(这是 Spring data JPA 语法,但 JPQL 的构造方式并不重要):
@Query("SELECT user FROM User user JOIN user.infoList info")
public List<User> getUsersJoin();
@Query("SELECT user FROM User user JOIN FETCH user.infoList info")
public List<User> getUsersJoinFetch();
Run Code Online (Sandbox Code Playgroud)
第一个仅包含JOIN关键字的查询将生成以下 SQL:
select u.id, u.email, u.name from test_user u
inner join test_user_data on u.id=test_user_data.user_id;
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,它只会从 test_user 表中获取数据,而不是从 test_user_data 表中获取数据。这也可以在调试器中看到,如下所示:
List<userData>可以看出,我们的对象上没有 ,User因为默认情况下不会加载它。
现在让我们检查一下为查询生成的 SQL JOIN FETCH:
select test_user.id, data.id, test_user.email, test_user.name,
data.data, data.user_id, data.user_id, data.id from test_user test_user
inner join test_user_data data on test_user.id=data.user_id
Run Code Online (Sandbox Code Playgroud)
可以看到,我们现在正在从连接中的 test_user 和 test_user_data 表中获取数据。这也可以在调试器中看到,如下所示:
可以看出,我们现在可以访问对象List<userData>内部User。
如果您将@oneToOne映射设置为FetchType.LAZY并使用第二个查询(因为您需要将 Department 对象作为 Employee 对象的一部分加载),Hibernate 将执行的操作是,它将发出查询来为它从 DB 获取的每个 Employee 对象获取 Department 对象。
稍后,在代码中,您可能会通过 Employee 到 Department 单值关联访问 Department 对象,并且 Hibernate 不会发出任何查询来获取给定 Employee 的 Department 对象。
请记住,Hibernate 仍然发出等于它已获取的员工数量的查询。如果您希望访问所有 Employee 对象的 Department 对象,Hibernate 将在上述两个查询中发出相同数量的查询
| 归档时间: |
|
| 查看次数: |
169026 次 |
| 最近记录: |