Hibernate(十四):HQL查询

Posted yy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Hibernate(十四):HQL查询相关的知识,希望对你有一定的参考价值。

背景

基于上两章节《Hibernate(十二):HQL查询(一)》、《Hibernate(十三):HQL查询(二),已经学习了一部分关于HQL的用法:

  1. HQL带参数查询
  2. HQL Order By排序查询
  3. HQL 设置实体参数查询
  4. HQL分页查询
  5. HQL命名语句查询
  6. HQL投影查询
  7. HQL报表查询

本章节将会学习:HQL(迫切)左外连接、HQL(迫切)内连接、总结关联级别运行时的检索策略。

HQL(迫切)左外连接

 迫切左外连接

1)LEFT JOIN FETCH 关键字表示迫切左外连接检索策略

2)list()方法返回的集合中存放实体对象的引用,每个Department对象关联的Employee结合都被初始化,存放所有关联的Employee的实体对象

3)查询结果中可能会被包含重复的元素,可以通过HashSet来过滤重复元素,也可以在hql语句中使用distinct.

测试代码:

 1     @Test
 2     public void testLeftJoinFetch() {
 3         String hql = "FROM Department d LEFT JOIN FETCH d.employees";
 4         List<Department> departs = session.createQuery(hql).list();
 5 
 6         System.out.println("直接左外连接查询结果集合个数:" + departs.size());
 7         Department depart = departs.get(0);
 8         System.out.println("直接左外连接查询结果集的第一个元素Department Name:" + depart.getName() + ",该department的Employees个数:" + depart.getEmployees().size());
 9 
10         departs = new ArrayList<>(new LinkedHashSet<>(departs));
11         System.out.println("使用LinkedHashSet排除重复项后集合个数:" + departs.size());
12 
13         hql = "Select Distinct d FROM Department d LEFT JOIN FETCH d.employees";
14         List<Department> departs2 = session.createQuery(hql).list();
15         System.out.println("使用Distinct排除重复项后集合个数:" + departs2.size());
16         for(Department department : departs2){
17             System.out.println("使用Distinct排除重复项后元素Department Name:" + department.getName() + ",该department的Employees个数:" + department.getEmployees().size());
18         }
19     }

执行sql及结果:

 1 Hibernate: 
 2     select
 3         department0_.ID as ID1_0_0_,
 4         employees1_.ID as ID1_1_1_,
 5         department0_.NAME as NAME2_0_0_,
 6         employees1_.NAME as NAME2_1_1_,
 7         employees1_.SALARY as SALARY3_1_1_,
 8         employees1_.EMAIL as EMAIL4_1_1_,
 9         employees1_.DEPARTMENT_ID as DEPARTME5_1_1_,
10         employees1_.DEPARTMENT_ID as DEPARTME5_1_0__,
11         employees1_.ID as ID1_1_0__ 
12     from
13         DX_DEPARTMENT department0_ 
14     left outer join
15         DX_EMPLOYEE employees1_ 
16             on department0_.ID=employees1_.DEPARTMENT_ID
17 直接左外连接查询结果集合个数:80
18 直接左外连接查询结果集的第一个元素Department Name:开发部门,该department的Employees个数:16
19 使用LinkedHashSet排除重复项后集合个数:5
20 Hibernate: 
21     select
22         distinct department0_.ID as ID1_0_0_,
23         employees1_.ID as ID1_1_1_,
24         department0_.NAME as NAME2_0_0_,
25         employees1_.NAME as NAME2_1_1_,
26         employees1_.SALARY as SALARY3_1_1_,
27         employees1_.EMAIL as EMAIL4_1_1_,
28         employees1_.DEPARTMENT_ID as DEPARTME5_1_1_,
29         employees1_.DEPARTMENT_ID as DEPARTME5_1_0__,
30         employees1_.ID as ID1_1_0__ 
31     from
32         DX_DEPARTMENT department0_ 
33     left outer join
34         DX_EMPLOYEE employees1_ 
35             on department0_.ID=employees1_.DEPARTMENT_ID
36 使用Distinct排除重复项后集合个数:5
37 使用Distinct排除重复项后元素Department Name:开发部门,该department的Employees个数:16
38 使用Distinct排除重复项后元素Department Name:测试部门,该department的Employees个数:16
39 使用Distinct排除重复项后元素Department Name:业务部门,该department的Employees个数:16
40 使用Distinct排除重复项后元素Department Name:财务部门,该department的Employees个数:16
41 使用Distinct排除重复项后元素Department Name:行政部门,该department的Employees个数:16

左外连接

1)LEFT JOIN 关键字表示左外连接查询

2)list()方法返回的集合中存放的是数组类型

3)根据配置文件来决定Employee集合的策略(以下测试代码,前提是employee.hbm.xml中没有配置join=\'fetch\'策略)

4)如果希望list()方法返回的集合中仅包含Department对象,可以在HQL查询语句中使用SELECT关键字。

测试代码:

 1     @Test
 2     public void testLeftJoin() {
 3         String hql = "FROM Department d LEFT JOIN d.employees";
 4         List<Department> departs = session.createQuery(hql).list();
 5 
 6         System.out.println("直接左外连接查询结果集合个数:" + departs.size());
 7         // 将会抛出异常:
 8         //Department depart = departs.get(0);
 9         //System.out.println("直接左外连接查询结果集的第一个元素Department Name:" + depart.getName() + ",该department的Employees个数:" + depart.getEmployees().size());
10 
11         // 排重无效
12         departs = new ArrayList<>(new LinkedHashSet<>(departs));
13         System.out.println("使用LinkedHashSet排除重复项后集合个数:" + departs.size());
14 
15         hql = "Select Distinct d FROM Department d LEFT JOIN d.employees";
16         List<Department> departs2 = session.createQuery(hql).list();
17         System.out.println("使用Distinct排除重复项后集合个数:" + departs2.size());
18         for(Department department : departs2){
19             System.out.println("使用Distinct排除重复项后元素Department Name:" + department.getName() + ",该department的Employees个数:" + department.getEmployees().size());
20         }
21     }

执行sql及结果

 1 Hibernate: 
 2     select
 3         department0_.ID as ID1_0_0_,
 4         employees1_.ID as ID1_1_1_,
 5         department0_.NAME as NAME2_0_0_,
 6         employees1_.NAME as NAME2_1_1_,
 7         employees1_.SALARY as SALARY3_1_1_,
 8         employees1_.EMAIL as EMAIL4_1_1_,
 9         employees1_.DEPARTMENT_ID as DEPARTME5_1_1_ 
10     from
11         DX_DEPARTMENT department0_ 
12     left outer join
13         DX_EMPLOYEE employees1_ 
14             on department0_.ID=employees1_.DEPARTMENT_ID
15 直接左外连接查询结果集合个数:80
16 使用LinkedHashSet排除重复项后集合个数:80
17 Hibernate: 
18     select
19         distinct department0_.ID as ID1_0_,
20         department0_.NAME as NAME2_0_ 
21     from
22         DX_DEPARTMENT department0_ 
23     left outer join
24         DX_EMPLOYEE employees1_ 
25             on department0_.ID=employees1_.DEPARTMENT_ID
26 使用Distinct排除重复项后集合个数:5
27 Hibernate: 
28     select
29         employees0_.DEPARTMENT_ID as DEPARTME5_1_0_,
30         employees0_.ID as ID1_1_0_,
31         employees0_.ID as ID1_1_1_,
32         employees0_.NAME as NAME2_1_1_,
33         employees0_.SALARY as SALARY3_1_1_,
34         employees0_.EMAIL as EMAIL4_1_1_,
35         employees0_.DEPARTMENT_ID as DEPARTME5_1_1_ 
36     from
37         DX_EMPLOYEE employees0_ 
38     where
39         employees0_.DEPARTMENT_ID=?
40 使用Distinct排除重复项后元素Department Name:开发部门,该department的Employees个数:16
41 Hibernate: 
42     select
43         employees0_.DEPARTMENT_ID as DEPARTME5_1_0_,
44         employees0_.ID as ID1_1_0_,
45         employees0_.ID as ID1_1_1_,
46         employees0_.NAME as NAME2_1_1_,
47         employees0_.SALARY as SALARY3_1_1_,
48         employees0_.EMAIL as EMAIL4_1_1_,
49         employees0_.DEPARTMENT_ID as DEPARTME5_1_1_ 
50     from
51         DX_EMPLOYEE employees0_ 
52     where
53         employees0_.DEPARTMENT_ID=?
54 使用Distinct排除重复项后元素Department Name:测试部门,该department的Employees个数:16
55 Hibernate: 
56     select
57         employees0_.DEPARTMENT_ID as DEPARTME5_1_0_,
58         employees0_.ID as ID1_1_0_,
59         employees0_.ID as ID1_1_1_,
60         employees0_.NAME as NAME2_1_1_,
61         employees0_.SALARY as SALARY3_1_1_,
62         employees0_.EMAIL as EMAIL4_1_1_,
63         employees0_.DEPARTMENT_ID as DEPARTME5_1_1_ 
64     from
65         DX_EMPLOYEE employees0_ 
66     where
67         employees0_.DEPARTMENT_ID=?
68 使用Distinct排除重复项后元素Department Name:业务部门,该department的Employees个数:16
69 Hibernate: 
70     select
71         employees0_.DEPARTMENT_ID as DEPARTME5_1_0_,
72         employees0_.ID as ID1_1_0_,
73         employees0_.ID as ID1_1_1_,
74         employees0_.NAME as NAME2_1_1_,
75         employees0_.SALARY as SALARY3_1_1_,
76         employees0_.EMAIL as EMAIL4_1_1_,
77         employees0_.DEPARTMENT_ID as DEPARTME5_1_1_ 
78     from
79         DX_EMPLOYEE employees0_ 
80     where
81         employees0_.DEPARTMENT_ID=?
82 使用Distinct排除重复项后元素Department Name:财务部门,该department的Employees个数:16
83 Hibernate: 
84     select
85         employees0_.DEPARTMENT_ID as DEPARTME5_1_0_,
86         employees0_.ID as ID1_1_0_,
87         employees0_.ID as ID1_1_1_,
88         employees0_.NAME as NAME2_1_1_,
89         employees0_.SALARY as SALARY3_1_1_,
90         employees0_.EMAIL as EMAIL4_1_1_,
91         employees0_.DEPARTMENT_ID as DEPARTME5_1_1_ 
92     from
93         DX_EMPLOYEE employees0_ 
94     where
95         employees0_.DEPARTMENT_ID=?
96 使用Distinct排除重复项后元素Department Name:行政部门,该department的Employees个数:16

HQL(迫切)内连接

 迫切内连接

1)INNER JOIN FETCH关键字表示迫切内连接,也可以省略INNER关键字

2)list()方法返回的集合中存放Department对象的引用,每个Department对象的Employee集合都被初始化,存放所有关联的Employee对象。

测试函数:

 1     @Test
 2     public void testInnerJoinFetch() {
 3         // // 先执行追加employee一条记录。
 4         // Employee employee = new Employee("name", 10000, "email@test.com");
 5         // session.save(employee);
 6         // Department department = new Department("党政部门");
 7         // session.save(department);
 8 
 9         String hql = "FROM Department d INNER JOIN FETCH d.employees";
10         List<Department> departs = session.createQuery(hql).list();
11 
12         System.out.println("直接左外连接查询结果集合个数:" + departs.size());
13         Department depart = departs.get(0);
14         System.out.println("直接左外连接查询结果集的第一个元素Department Name:" + depart.getName() + ",该department的Employees个数:" + depart.getEmployees().size());
15 
16         departs = new ArrayList<>(new LinkedHashSet<>(departs));
17         System.out.println("使用LinkedHashSet排除重复项后集合个数:" + departs.size());
18 
19         hql = "Select Distinct d FROM Department d INNER JOIN FETCH d.employees";
20         List<Department> departs2 = session.createQuery(hql).list();
21         System.out.println("使用Distinct排除重复项后集合个数:" + departs2.size());
22         for (Department department : departs2) {
23             System.out.println("使用Distinct排除重复项后元素Department Name:" + department.getName() + ",该department的Employees个数:" + department.getEmployees().size());
24         }
25     }

执行sql及结果:

 1 Hibernate: 
 2     select
 3         department0_.ID as ID1_0_0_,
 4         employees1_.ID as ID1_1_1_,
 5         department0_.NAME as NAME2_0_0_,
 6         employees1_.NAME as NAME2_1_1_,
 7         employees1_.SALARY as SALARY3_1_1_,
 8         employees1_.EMAIL as EMAIL4_1_1_,
 9         employees1_.DEPARTMENT_ID as DEPARTME5_1_1_,
10         employees1_.DEPARTMENT_ID as DEPARTME5_1_0__,
11         employees1_.ID as ID1_1_0__ 
12     from
13         DX_DEPARTMENT department0_ 
14     inner join
15         DX_EMPLOYEE employees1_ 
16             on department0_.ID=employees1_.DEPARTMENT_ID
17 直接左外连接查询结果集合个数:80
18 直接左外连接查询结果集的第一个元素Department Name:开发部门,该department的Employees个数:16
19 使用LinkedHashSet排除重复项后集合个数:5
20 Hibernate: 
21     select
22         distinct department0_.ID as ID1_0_0_,
23         employees1_.ID as ID1_1_1_,
24         department0_.NAME as NAME2_0_0_,
25         employees1_.NAME as NAME2_1_1_,
26         employees1_.SALARY as SALARY3_1_1_,
27         employees1_.EMAIL as EMAIL4_1_1_,
28         employees1_.DEPARTMENT_ID as DEPARTME5_1_1_,
29         employees1_.DEPARTMENT_ID as DEPARTME5_1_0__,
30         employees1_.ID as ID1_1_0__ 
31     from
32         DX_DEPARTMENT department0_ 
33     inner join
34         DX_EMPLOYEE employees1_ 
35             on department0_.ID=employees1_.DEPARTMENT_ID
36 使用Distinct排除重复项后集合个数:5
37 使用Distinct排除重复项后元素Department Name:开发部门,该department的Employees个数:16
38 使用Distinct排除重复项后元素Department Name:测试部门,该department的Employees个数:16
39 使用Distinct排除重复项后元素Department Name:业务部门,该department的Employees个数:16
40 使用Distinct排除重复项后元素Department Name:财务部门,该department的Employees个数:16
41 使用Distinct排除重复项后元素Department Name:行政部门,该department的Employees个数:16

内连接

1)INNER JOIN 关键字表示内连接,也可以省略INNER 关键字

2)list()方法的集合中存放的每个元素对应查询结果的一条记录,每个元素都是对象数组

3)如果希望list()方法的返回集合仅包含Department对象,可以在HQL查询语句中使用SELECT关键字。

测试函数:

 1     @Test
 2     public void testInnerJoin() {
 3         String hql = "FROM Department d INNER JOIN d.employees";
 4         List<Department> departs = session.createQuery(hql).list();
 5 
 6         System.out.println("直接左外连接查询结果集合个数:" + departs.size());
 7         // 将会抛出异常:
 8         // Department depart = departs.get(0);
 9         // System.out.println("直接左外连接查询结果集的第一个元素Department Name:"
10         // +depart.getName() + ",该department的Employees个数:" +
11         // depart.getEmployees().size());
12 
13         // 排重无效
14         departs = new ArrayList<>(new LinkedHashSet<>(departs));
15         System.out.println("使用LinkedHashSet排除重复项后集合个数:" + departs.size());
16 
17         hql = "Select Distinct d FROM Department d INNER JOIN d.employees";
18         List<Department> departs2 = session.createQuery(hql).list();
19         System.out.println("使用Distinct排除重复项后集合个数:" + departs2.size());
20         for (Department department : departs2) {
21             System.out.println("使用Distinct排除重复项后元素Department Name:" + department.getName() + ",该department的Employees个数:" + department.getEmployees().size());
22         }
23     }

执行sql及结果:

 1 Hibernate: 
 2     select
 3         department0_.ID as ID1_0_0_,
 4         employees1_.ID as ID1_1_1_,
 5         department0_.NAME as NAME2_0_0_,
 6         employees1_.NAME as NAME2_1_1_,
 7         employees1_.SALARY as SALARY3_1_1_,
 8         employees1_.EMAIL as EMAIL4_1_1_,
 9         employees1_.DEPARTMENT_ID as DEPARTME5_1_1_ 
10     from
11         DX_DEPARTMENT department0_ 
12     inner join
13         DX_EMPLOYEE employees1_ 
14             on department0_.ID=employees1_.DEPARTMENT_ID
15 直接左外连接查询结果集合个数:80
16 使用LinkedHashSet排除重复项后集合个数:80
17 Hibernate: 
18     select
19         distinct department0_.ID as ID1_0_,
20         department0_.NAME as NAME2_0_ 
21     from
22         DX_DEPARTMENT department0_ 
23     inner join
24         DX_EMPLOYEE employees1_ 
25             on department0_.ID=employees1_.DEPARTMENT_ID
26 使用Distinct排除重复项后集合个数:5
27 Hibernate: 
28     select
29         employees0_.DEPARTMENT_ID as DEPARTME5_1_0_,
30         employees0_.ID as ID1_1_0_,
31         employees0_.ID as ID1_1_1_,
32         employees0_.NAME as NAME2_1_1_,
33         employees0_.SALARY as SALARY3_1_1_,
34         employees0_.EMAIL as EMAIL4_1_1_,
35         employees0_.DEPARTMENT_ID as DEPARTME5_1_1_ 
36     from
37         DX_EMPLOYEE employees0_ 
38     where
39         employees0_.DEPARTMENT_ID=?
40 使用Distinct排除重复项后元素Department Name:开发部门,该department的Employees个数:16
41 Hibernate: 
42     select
43         employees0_.DEPARTMENT_ID as DEPARTME5_1_0_,
44         employees0_.ID as ID1_1_0_,
45         employees0_.ID as ID1_1_1_,
46         employees0_.NAME as NAME2_1_1_,
47         employees0_.SALARY as SALARY3_1_1_,
48         employees0_.EMAIL as EMAIL4_1_1_,
49         employees0_.DEPARTMENT_ID as DEPARTME5_1_1_ 
50     from
51         DX_EMPLOYEE employees0_ 
52     where
53         employees0_.DEPARTMENT_ID=?
54 使用Distinct排除重复项后元素Department Name:测试部门,该department的Employees个数:16
55 Hibernate: 
56     select
57         employees0_.DEPARTMENT_ID as DEPARTME5_1_0_,
58         employees0_.ID as ID1_1_0_,
59         employees0_.ID as ID1_1_1_,
60         employees0_.NAME as NAME2_1_1_,
61         employees0_.SALARY as SALARY3_1_1_,
62         employees0_.EMAIL as EMAIL4_1_1_,
63         employees0_.DEPARTMENT_ID as DEPARTME5_1_1_ 
64     from
65         DX_EMPLOYEE employees0_ 
66     where
67         employees0_.DEPARTMENT_ID=?
68 使用Distinct排除重复项后元素Department Name:业务部门,该department的Employees个数:16
69 Hibernate: 
70     select
71         employees0_.DEPARTMENT_ID as DEPARTME5_1_0_,
72         employees0_.ID as ID1_1_0_,
73         employees0_.ID as ID1_1_1_,
74         employees0_.NAME as NAME2_1_1_,
75         employees0_.SALARY as SALARY3_1_1_,
76         employees0_.EMAIL as EMAIL4_1_1_,
77         employees0_.DEPARTMENT_ID as DEPARTME5_1_1_ 
78     from
79         DX_EMPLOYEE employees0_ 
80     where
81         employees0_.DEPARTMENT_ID=?
82 使用Distinct排除重复项后元素Department Name:财务部门,该department的Employees个数:16
83 Hibernate: 
84     select
85         employees0_.DEPARTMENT_ID as DEPARTME5_1_0_,
86         employees0_.ID as ID1_1_0_,
87         employees0_.ID as ID1_1_1_,
88         employees0_.NAME as NAME2_1_1_,
89         employees0_.SALARY as SALARY3_1_1_,
90         employees0_.EMAIL as EMAIL4_1_1_,
91         employees0_.DEPARTMENT_ID as DEPARTME5_1_1_ 
92     from
93         DX_EMPLOYEE employees0_ 
94     where
95         employees0_.DEPARTMENT_ID=?
96 使用Distinct排除重复项后元素Department Name:行政部门,该department的Employees个数:16

总结关联级别运行时的检索策略

1)如果在HQL中没有显式指定检索策略,将使用映射文件配置的检索策略

2)HQL会忽略映射文件中设置的迫切左外连接检索策略,如果HQL采用迫切左外连接策略,就必须在HQL查询语句中显式的指定它

3)若在HQL代码中显式指定了检索策略,就会覆盖映射文件中配置的检索策略。

 

以上是关于Hibernate(十四):HQL查询的主要内容,如果未能解决你的问题,请参考以下文章

Hibernate命名查询

Hibernate HQL中的子查询

转: Hibernate HQL查询 插入 更新(update)实例

Hibernate HQL查询语句总结

Hibernate中Hql查询

hibernate hql查询 与Criteria 查询语句区别和效率