Hibernate检索方式-HQL
Hibernate 提供了以下几种检索对象的方式
(1)导航对象图检索方式: 根据已经加载的对象导航到其他对象
(2)OID 检索方式: 按照对象的 OID 来检索对象
(3)HQL 检索方式: 使用面向对象的 HQL 查询语言
(4)QBC 检索方式: 使用 QBC(Query By Criteria) API 来检索对象. 这种 API 封装了基于字符串形式的查询语句, 提供了更加面向对象的查询接口.
(5)本地 SQL 检索方式: 使用本地数据库的 SQL 查询语句
HQL(Hibernate Query Language) 是面向对象的查询语言, 它和 SQL 查询语言有些相似. 在 Hibernate 提供的各种检索方式中, HQL 是使用最广的一种检索方式. 它有如下功能:
(1)在查询语句中设定各种查询条件
(2)支持投影查询, 即仅检索出对象的部分属性
(3)支持分页查询
(4)支持连接查询
(5)支持分组查询, 允许使用 HAVING 和 GROUP BY 关键字
(6)提供内置聚集函数, 如 sum(), min() 和 max()
(7)支持子查询
(8)支持动态绑定参数
(9)能够调用 用户定义的 SQL 函数或标准的 SQL 函数
HQL 检索方式包括以下步骤:
(1)通过 Session 的 createQuery() 方法创建一个 Query 对象, 它包括一个 HQL 查询语句. HQL 查询语句中可以包含命名参数
(2)动态绑定参数
(3)调用 Query 相关方法执行查询语句.
Qurey 接口支持方法链编程风格, 它的 setXxx() 方法返回自身实例, 而不是 void 类型
HQL vs SQL:
1.HQL 查询语句是面向对象的, Hibernate 负责解析 HQL 查询语句, 然后根据对象-关系映射文件中的映射信息, 把 HQL 查询语句翻译成相应的 SQL 语句. HQL 查询语句中的主体是域模型中的类及类的属性
2.SQL 查询语句是与关系数据库绑定在一起的. SQL 查询语句中的主体是数据库表及表的字段.
绑定参数:
1.Hibernate 的参数绑定机制依赖于 JDBC API 中的 PreparedStatement 的预定义 SQL 语句功能.
2.HQL 的参数绑定由两种形式:
(1)按参数名字绑定: 在 HQL 查询语句中定义命名参数, 命名参数以 “:” 开头.
(2)按参数位置绑定: 在 HQL 查询语句中用 “?” 来定义参数位置
3.相关方法:
(1)setEntity(): 把参数与一个持久化类绑定
(2)setParameter(): 绑定任意类型的参数. 该方法的第三个参数显式指定 Hibernate 映射类型
HQL 采用 ORDER BY 关键字对查询结果排序
分页查询:
1.setFirstResult(int firstResult): 设定从哪一个对象开始检索, 参数 firstResult 表示这个对象在查询结果中的索引位置, 索引位置的起始值为 0. 默认情况下, Query 从查询结果中的第一个对象开始检索
2.setMaxResults(int maxResults): 设定一次最多检索出的对象的数目. 在默认情况下, Query 和 Criteria 接口检索出查询结果中所有的对象
在映射文件中定义命名查询语句
Hibernate 允许在映射文件中定义字符串形式的查询语句.
<query> 元素用于定义一个 HQL 查询语句, 它和 <class> 元素并列.
@Test public void testPageQuery(){ String hql = "FROM Employee"; Query query = session.createQuery(hql); int pageNo = 22; int pageSize = 5; List<Employee> emps = query.setFirstResult((pageNo - 1) * pageSize) .setMaxResults(pageSize) .list(); System.out.println(emps); }

在程序中通过 Session 的 getNamedQuery() 方法获取查询语句对应的 Query 对象.
//命名查询,语句放在xml中 @Test public void testNamedQuery(){ Query query = session.getNamedQuery("salaryEmps"); List<Employee> emps = query.setFloat("minSal", 5000) .setFloat("maxSal", 10000) .list(); System.out.println(emps.size()); }
投影查询:
投影查询: 查询结果仅包含实体的部分属性. 通过 SELECT 关键字实现.
Query 的 list() 方法返回的集合中包含的是数组类型的元素, 每个对象数组代表查询结果的一条记录
可以在持久化类中定义一个对象的构造器来包装投影查询返回的记录, 使程序代码能完全运用面向对象的语义来访问查询结果集.
可以通过 DISTINCT 关键字来保证查询结果不会返回重复元素
@Test public void testFieldQuery(){ String hql = "SELECT e.email, e.salary, e.dept FROM Employee e WHERE e.dept = :dept"; Query query = session.createQuery(hql); Department dept = new Department(); dept.setId(80); List<Object[]> result = query.setEntity("dept", dept) .list(); for(Object [] objs: result){ System.out.println(Arrays.asList(objs)); } }
@Test public void testFieldQuery2(){ String hql = "SELECT new Employee(e.email, e.salary, e.dept) " + "FROM Employee e " + "WHERE e.dept = :dept"; Query query = session.createQuery(hql); Department dept = new Department(); dept.setId(80); List<Employee> result = query.setEntity("dept", dept) .list(); for(Employee emp: result){ System.out.println(emp.getId() + ", " + emp.getEmail() + ", " + emp.getSalary() + ", " + emp.getDept()); } }
报表查询
报表查询用于对数据分组和统计, 与 SQL 一样, HQL 利用 GROUP BY 关键字对数据分组, 用 HAVING 关键字对分组数据设定约束条件.
在 HQL 查询语句中可以调用以下聚集函数:count() min() max() sum() avg()
@Test public void testGroupBy(){ String hql = "SELECT min(e.salary), max(e.salary) " + "FROM Employee e " + "GROUP BY e.dept " + "HAVING min(salary) > :minSal"; Query query = session.createQuery(hql) .setFloat("minSal", 8000); List<Object []> result = query.list(); for(Object [] objs: result){ System.out.println(Arrays.asList(objs)); } }
HQL (迫切)左外连接
LEFT JOIN FETCH 关键字表示迫切左外连接检索策略.
list() 方法返回的集合中存放实体对象的引用, 每个 Department 对象关联的 Employee 集合都被初始化, 存放所有关联的 Employee 的实体对象.
查询结果中可能会包含重复元素, 可以通过一个 HashSet 来过滤重复元素
@Test public void testLeftJoinFetch(){ // String hql = "SELECT DISTINCT d FROM Department d LEFT JOIN FETCH d.emps"; String hql = "FROM Department d INNER JOIN FETCH d.emps"; Query query = session.createQuery(hql); List<Department> depts = query.list(); depts = new ArrayList<>(new LinkedHashSet(depts));//去除重复 System.out.println(depts.size()); for(Department dept: depts){ System.out.println(dept.getName() + "-" + dept.getEmps().size()); } }
左外连接:
LEFT JOIN 关键字表示左外连接查询.
list() 方法返回的集合中存放的是对象数组类型
根据配置文件来决定 Employee 集合的检索策略.
如果希望 list() 方法返回的集合中仅包含 Department 对象, 可以在HQL 查询语句中使用 SELECT 关键字
@Test public void testLeftJoin(){ String hql = "SELECT DISTINCT d FROM Department d LEFT JOIN d.emps"; Query query = session.createQuery(hql); List<Department> depts = query.list(); System.out.println(depts.size()); for(Department dept: depts){ System.out.println(dept.getName() + ", " + dept.getEmps().size()); } // List<Object []> result = query.list(); // result = new ArrayList<>(new LinkedHashSet<>(result)); // System.out.println(result); // // for(Object [] objs: result){ // System.out.println(Arrays.asList(objs)); // } }
HQL (迫切)内连接
INNER JOIN FETCH 关键字表示迫切内连接, 也可以省略 INNER 关键字
list() 方法返回的集合中存放 Department 对象的引用, 每个 Department 对象的 Employee 集合都被初始化, 存放所有关联的 Employee 对象
内连接:
INNER JOIN 关键字表示内连接, 也可以省略 INNER 关键字
list() 方法的集合中存放的每个元素对应查询结果的一条记录, 每个元素都是对象数组类型
如果希望 list() 方法的返回的集合仅包含 Department 对象, 可以在 HQL 查询语句中使用 SELECT 关键字
@Test public void testLeftJoinFetch2(){ String hql = "SELECT e FROM Employee e INNER JOIN e.dept"; Query query = session.createQuery(hql); List<Employee> emps = query.list(); System.out.println(emps.size()); for(Employee emp: emps){ System.out.println(emp.getName() + ", " + emp.getDept().getName()); } }
关联级别运行时的检索策略
如果在 HQL 中没有显式指定检索策略, 将使用映射文件配置的检索策略.
HQL 会忽略映射文件中设置的迫切左外连接检索策略, 如果希望 HQL 采用迫切左外连接策略, 就必须在 HQL 查询语句中显式的指定它
若在 HQL 代码中显式指定了检索策略, 就会覆盖映射文件中配置的检索策略
浙公网安备 33010602011771号