一、HQL检索方式
HQL(Hibernate Query Language) 是面向对象的查询语言, 它和 SQL 查询语言有些相似.
在 Hibernate 提供的各种检索方式中, HQL 是使用最广的一种检索方式. 它有如下功能:
- 在查询语句中设定各种查询条件
- 支持投影查询, 即仅检索出对象的部分属性
- 支持分页查询
- 支持连接查询
- 支持分组查询, 允许使用 HAVING 和 GROUP BY 关键字
- 提供内置聚集函数, 如 sum(), min() 和 max()
- 支持子查询
- 支持动态绑定参数
- 能够调用 用户定义的 SQL 函数或标准的 SQL 函数
二、HQL 检索方式步骤
- 通过 Session 的 createQuery() 方法创建一个 Query 对象, 它包括一个 HQL 查询语句. HQL 查询语句中可以包含命名参数
- 动态绑定参数
- 调用 Query 相关方法执行查询语句.
Qurey 接口支持方法链编程风格, 它的 setXxx() 方法返回自身实例, 而不是 void 类型HQL vs SQL:
- HQL 查询语句是面向对象的, Hibernate 负责解析 HQL 查询语句, 然后根据对象-关系映射文件中的映射信息, 把 HQL 查询语句翻译成相应的 SQL 语句.
- HQL 查询语句中的主体是域模型中的类及类的属性
- SQL 查询语句是与关系数据库绑定在一起的. SQL 查询语句中的主体是数据库表及表的字段.
java 实体类package com.weixuan.hql; public class Employee { private Integer employeeID; private String employeeName; private float salary; private String email; private Department department; public Integer getEmployeeID() { return employeeID; } public void setEmployeeID(Integer employeeID) { this.employeeID = employeeID; } public String getEmployeeName() { return employeeName; } public void setEmployeeName(String employeeName) { this.employeeName = employeeName; } public float getSalary() { return salary; } public void setSalary(float salary) { this.salary = salary; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public Department getDepartment() { return department; } public void setDepartment(Department department) { this.department = department; } @Override public String toString() { return "Employee [employeeID=" + employeeID + ", employeeName=" + employeeName + ", salary=" + salary + ", email=" + email + ", department=" + department + "]"; } public Employee() { super(); } public Employee(String employeeName, float salary, String email) { super(); this.employeeName = employeeName; this.salary = salary; this.email = email; } }
package com.weixuan.hql; import java.util.HashSet; import java.util.Set; public class Department { private Integer departmentID; private String departmentName; private Set<Employee> se = new HashSet<Employee>(); public Integer getDepartmentID() { return departmentID; } public void setDepartmentID(Integer departmentID) { this.departmentID = departmentID; } public String getDepartmentName() { return departmentName; } public void setDepartmentName(String departmentName) { this.departmentName = departmentName; } public Set<Employee> getSe() { return se; } public void setSe(Set<Employee> se) { this.se = se; } }
测试文件
@Test public void testhql() { /** * 1、创建query对象 2、绑定参数 3、执行查询 */ // 使用位置参数,还可以使用order by String hql = "FROM Employee e where e.salary > ? " + "and e.email like ? order by e.salary"; Query query = session.createQuery(hql); // 0,1 分别代表参数位置 // set方法返回值还是query,可以一直set下去 query.setFloat(0, 100000).setString(1, "%qq%"); List<Employee> lemp = query.list(); System.out.println(lemp.get(0).getEmployeeName()); } @Test public void testhql_1() { // 使用命名参数 String hql = "FROM Employee e where e.salary > :sal " + "and e.email like :email " + "and e.department= :dep"; Query query = session.createQuery(hql); Department dept = new Department(); dept.setDepartmentID(1); // 0,1 分别代表参数位置 query.setFloat("sal", 10000).setString("email", "%qq%") .setEntity("dep", dept); List<Employee> lemp = query.list(); System.out.println(lemp.size()); }
三、四个小细节
1、分页查询:
- setFirstResult(int firstResult): 设定从哪一个对象开始检索, 参数 firstResult 表示这个对象在查询结果中的索引位置, 索引位置的起始值为 0.
- 默认情况下, Query 从查询结果中的第一个对象开始检索
- setMaxResults(int maxResults): 设定一次最多检索出的对象的数目. 在默认情况下, Query 和 Criteria 接口检索出查询结果中所有的对象
// 测试分页查询 @Test public void testPageQuery() { String hql = "From Employee "; Query query = session.createQuery(hql); int pageno = 2; int maxPage = 5; List<Employee> le = query.setFirstResult((pageno - 1) * maxPage) .setMaxResults(maxPage).list(); System.out.println(le); }
2、命名查询
- 在映射文件中定义命名查询语句
- Hibernate 允许在映射文件中定义字符串形式的查询语句.<query> 元素用于定义一个 HQL 查询语句, 它和 <class> 元素并列.
- 在程序中通过 Session 的 getNamedQuery() 方法获取查询语句对应的 Query 对象.
<!-- 命名查询 --> <!-- 防止发生歧义,放在cdata里面 --> <query name="selectQuery"><![CDATA[From Employee e where e.salary > :minsal and e.salary< :maxsal]]></query>
// 测试命名查询 @Test public void testNamedQuery() { Query query = session.getNamedQuery("selectQuery"); List<Employee> le = query.setFloat("minsal", 10000) .setFloat("maxsal", 1000000).list(); System.out.println(le); System.out.println(le.size()); }
3、投影查询: 查询结果仅包含实体的部分属性. 通过 SELECT 关键字实现.
- Query 的 list() 方法返回的集合中包含的是数组类型的元素, 每个对象数组代表查询结果的一条记录
- 可以在持久化类中定义一个对象的构造器来包装投影查询返回的记录, 使程序代码能完全运用面向对象的语义来访问查询结果集.
- 可以通过 DISTINCT 关键字来保证查询结果不会返回重复元素
// 测试投影查询 ,普通的数组操作,很麻烦 @Test public void testpropertyQuery() { String hql = "select e.employeeName," + "e.salary,e.email From Employee e " + "where e.department = :dep"; Query query = session.createQuery(hql); Department dep = new Department(); dep.setDepartmentID(3); List<Object[]> lo = query.setEntity("dep", dep).list(); for (Object[] obj : lo) System.out.println(Arrays.asList(obj)); } // 测试投影查询,能不能返回一个employee? 在实体类添加构造器 @Test public void testpropertyQuery_1() { String hql = "select new Employee(e.employeeName,e.salary,e.email)" + "From Employee e " + "where e.department = :dep"; Query query = session.createQuery(hql); Department dep = new Department(); dep.setDepartmentID(3); List<Employee> emps = query.setEntity("dep", dep).list(); for (Employee e : emps) System.out.println(e); }
public Employee(String employeeName, float salary, String email) { super(); this.employeeName = employeeName; this.salary = salary; this.email = email; }
4、报表查询
用于对数据分组和统计, 与 SQL 一样, HQL 利用 GROUP BY 关键字对数据分组, 用 HAVING 关键字对分组数据设定约束条件.
在 HQL 查询语句中可以调用以下聚集函数count() min() max() sum() avg()
// 报表查询 @Test public void testGroupByQuery() { String hql = "select min(e.salary),max(e.salary) from Employee e " + "group by e.department " + "HAVING min(salary)>:minsal"; Query query = session.createQuery(hql).setFloat("minsal", 2000); List<Object[]> res = query.list(); for (Object[] objs : res) System.out.println(Arrays.asList(objs)); }