Hibernate(十四):HQL查询(三)
背景
基于上两章节《Hibernate(十二):HQL查询(一)》、《Hibernate(十三):HQL查询(二)》,已经学习了一部分关于HQL的用法:
- HQL带参数查询
- HQL Order By排序查询
- HQL 设置实体参数查询
- HQL分页查询
- HQL命名语句查询
- HQL投影查询
- 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代码中显式指定了检索策略,就会覆盖映射文件中配置的检索策略。
基础才是编程人员应该深入研究的问题,比如:
1)List/Set/Map内部组成原理|区别
2)mysql索引存储结构&如何调优/b-tree特点、计算复杂度及影响复杂度的因素。。。
3)JVM运行组成与原理及调优
4)Java类加载器运行原理
5)Java中GC过程原理|使用的回收算法原理
6)Redis中hash一致性实现及与hash其他区别
7)Java多线程、线程池开发、管理Lock与Synchroined区别
8)Spring IOC/AOP 原理;加载过程的。。。
【+加关注】。