首页 > 代码库 > Hibernate之HQL介绍

Hibernate之HQL介绍

Hibernate中提供了多种检索对象的方式,主要包括以下种类:

  1. 导航对象图检索方式:根据已经加载的对象导航到其他对象
  2. OID检索方式:根据对象的OID来检索对象
  3. HQL检索方式:使用面向对象的HQL查询语言
  4. QBC检索方式:使用QBC(Query By Criteria)API来检索对象。这种API封装了基于字符串形式的查询语句,提供了更加面向对象的查询接口
  5. 本地SQL检索方式:使用本地数据库的SQL查询语句

本文主要介绍第三种方式,也就是HQL检索对象。

HQL(Hibernate Query Language)是面向对象的查询语言,它和SQL查询语言有些相似。在Hibernate提供的各种检索方式中,HQL是使用最广的一种检索方式。它有如下功能:

  • 在查询语句中设定各种查询条件
  • 支持投影查询,即仅检索出对象的部分属性
  • 支持分页查询
  • 支持连接查询
  • 支持分组查询,允许使用HAVING和GROUP BY关键字
  • 提供内置聚集函数,如sum(), min()和max()
  • 支持子查询
  • 支持动态绑定参数
  • 能够调用用户定义的SQL函数或标准的SQL函数

HQL检索方式包括以下步骤:

  • 通过Session的createQuery()方法创建一个Query对象,它包括一个HQL查询语句,HQL查询语句可以包含命名参数
  • 动态绑定参数
  • 调用Query相关方法执行查询语句

 

Query接口支持方法链编程风格,它的setXxx()方法返回自身实例,而不是void类型。

HQL vs SQL:

  • HQL查询语句是面向对象的,Hibernate负责解析HQL查询语句,然后根据对象-关系映射文件中的映射信息,把HQL查询语句翻译成相应的SQL语句,HQL查询语句中的主体是域模型中的类及类的属性
  • SQL查询语句是与关系数据库绑定在一起的。SQL查询语句中的主体是数据库表及表的字段

绑定参数:

  • Hibernate的参数绑定机制依赖于JDBC API中的PreparedStatement的预定义SQL语句功能
  • Hibernate的参数绑定有两种形式:

    1.按参数名字绑定:在HQL查询语句中定义命名参数,命名参数以":"开头

    2.按参数位置绑定:在HQL查询语句中用"?"来定义参数位置

  • 相关方法:

    1.setEntity():把参数与一个持久化类绑定

    2.setParameter(): 绑定任意类型的参数,该方法的第三个参数显式指定Hibernate映射类型

  • HQL采用ORDER BY关键字对查询结果排序

 

下面详细介绍下Hibernate的HQL的几个功能:

分页查询:

  • setFirstResult(int firstResult): 设定从哪一个对象开始检索,参数firstResult表示这个对象在查询结果中的索引位置,索引位置的起始值为0.默认情况下,Query从查询结果中的第一个对象开始检索
  • setMaxResult(int maxResults): 设定一次最多检索出的对象的数目。在默认情况下,Query和Criteria接口检索出查询结果中所有的对象

在映射文件中定义命名查询语句

  • Hibernate允许在映射文件中定义字符串形式的查询语句
  • <query>元素用于定义一个HQL查询语句,它和<class>元素并列

    <query name="salaryEmps"><![CDATA[FROM Employee w WHERE e.salary > :minSal AND e.salary < :maxSal]]></query>

  • 在程序中通过Session的getNamedQuery()方法获取查询语句对应的Query对象

投影查询

  • 投影查询:查询结果仅包含实体的部分属性。通过SELECT关键字实现
  • Query的list()方法返回的集合中包含的是数组类型的元素,每个对象数组代表查询结果的一条记录
  • 可以在持久化类中定义一个对象的构造器来包装投影查询返回的记录,使程序代码能完全运用面向对象的语义来访问查询结果集
  • 可以通过DISTINCT关键字来保证查询结果不会返回重复元素

报表查询

  • 报表查询用于对数据分组和统计,与SQL一样,HQL利用GROUP BY关键字对数据分组,用HAVING关键字对分组数据设定约束条件
  • 在HQL查询语句中可以调用以下聚集函数
    • count()
    • min()
    • max()
    • sum()
    • avg()  

HQL(迫切)左外连接

  • 迫切左外连接:
    • LEFT JOIN FETCH关键字表示迫切左外连接检索策略
    • list()方法返回的集合中存放实体对象的引用,每个Department对象关联的Employee集合都被初始化,存放所有关联的Employee的实体对象
    • 查询结果中可能会包含重复元素,可以通过一个HashSet来过滤重复元素

  • 左外连接:
    • LEFT JOIN关键字表示左外连接
    • list()方法返回的集合中存放的是对象数组类型
    • 根据配置文件来决定Employee集合的检索策略
    • 如果希望list()方法返回的集合中仅包含Department对象,可以在HQL查询语句中使用SELECT关键字

HQL(迫切)内连接

  • 迫切内连接:
    • INNER JOIN FETCH关键字表示迫切内连接,也可以省略INNER关键字
    • list()方法返回的集合中存放Department对象的引用,每个Department对象的Employee集合都被初始化,存放所有关联的Employee对象
  • 内连接
    • INNER JOIN关键字表示内连接,也可以省略INNER关键字
    • list()方法的集合中存放的每个元素对应查询结果的一条记录,每个元素都是对象数组类型
    • 如果希望list()方法的返回的集合仅包含Department对象,可以在HQL查询语句中使用SELECT关键字

 

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

  • 如果在HQL中没有显式指定检索策略,将使用映射文件配置的检索策略
  • HQL会忽略映射文件中设置的迫切左外连接检索策略,如果希望HQL采用迫切左外连接策略,就必须在HQL查询语句中显式指定它
  • 若在HQL代码中显式指定了检索策略,就会覆盖映射文件中配置的检索策略

==============================代码区========================================

Department.java

 1 package com.yl.hibernate.entities; 2  3 import java.util.HashSet; 4 import java.util.Set; 5  6 public class Department { 7      8     private Integer id; 9     private String name;10     11     private Set<Employee> emps = new HashSet<Employee>();12 13     public Integer getId() {14         return id;15     }16 17     public void setId(Integer id) {18         this.id = id;19     }20 21     public String getName() {22         return name;23     }24 25     public void setName(String name) {26         this.name = name;27     }28 29     public Set<Employee> getEmps() {30         return emps;31     }32 33     public void setEmps(Set<Employee> emps) {34         this.emps = emps;35     }36 37     @Override38     public String toString() {39         //return "Department [id=" + id + ", name=" + name + "]";40         return "Department [id=" + id + "]";41     }42             43 }

Employee.java

 1 package com.yl.hibernate.entities; 2  3 public class Employee { 4      5     private Integer id; 6     private String name; 7     private float salary; 8     private String email; 9     10     private Department dept;11 12     public Integer getId() {13         return id;14     }15 16     public void setId(Integer id) {17         this.id = id;18     }19 20     public String getName() {21         return name;22     }23 24     public void setName(String name) {25         this.name = name;26     }27 28     public float getSalary() {29         return salary;30     }31 32     public void setSalary(float salary) {33         this.salary = salary;34     }35 36     public String getEmail() {37         return email;38     }39 40     public void setEmail(String email) {41         this.email = email;42     }43 44     public Department getDept() {45         return dept;46     }47 48     public void setDept(Department dept) {49         this.dept = dept;50     }51 52     @Override53     public String toString() {54         return "Employee [id=" + id + "]";55     }56 57     public Employee(){}58     59     public Employee(String email, float salary, Department dept) {60         super();61         this.salary = salary;62         this.email = email;63         this.dept = dept;64     }65     66 }

Department.hbm.xml

 1 <?xml version="1.0"?> 2 <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 3 "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> 4 <!-- Generated 2014-12-1 19:29:32 by Hibernate Tools 3.4.0.CR1 --> 5 <hibernate-mapping> 6     <class name="com.yl.hibernate.entities.Department" table="YL_DEPARTMENT"> 7         <id name="id" type="java.lang.Integer"> 8             <column name="ID" /> 9             <generator class="native" />10         </id>11         <property name="name" type="java.lang.String">12             <column name="NAME" />13         </property>14         <set name="emps" table="YL_EMPLOYEE" inverse="true" lazy="true">15             <key>16                 <column name="DEPT_ID" />17             </key>18             <one-to-many class="com.yl.hibernate.entities.Employee" />19         </set>20     </class>21 </hibernate-mapping>

Employee.hbm.xml

 1 <?xml version="1.0"?> 2 <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 3 "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> 4 <!-- Generated 2014-12-1 19:29:32 by Hibernate Tools 3.4.0.CR1 --> 5 <hibernate-mapping> 6     <class name="com.yl.hibernate.entities.Employee" table="YL_EMPLOYEE"> 7         <id name="id" type="java.lang.Integer"> 8             <column name="ID" /> 9             <generator class="native" />10         </id>11         <property name="name" type="java.lang.String">12             <column name="NAME" />13         </property>14         <property name="salary" type="float">15             <column name="SALARY" />16         </property>17         <property name="email" type="java.lang.String">18             <column name="EMAIL" />19         </property>20         <many-to-one name="dept" class="com.yl.hibernate.entities.Department" fetch="join">21             <column name="DEPT_ID" />22         </many-to-one>23     </class>24     25     <query name="salaryEmps"><![CDATA[FROM Employee e WHERE e.salary > :minSal AND e.salary < :maxSal]]></query>26     27 </hibernate-mapping>

测试类:

  1 package com.yl.hibernate.test;  2   3   4 import java.util.ArrayList;  5 import java.util.Arrays;  6 import java.util.LinkedHashSet;  7 import java.util.List;  8 import java.util.Set;  9  10 import oracle.net.aso.e; 11  12 import org.hibernate.Query; 13 import org.hibernate.Session; 14 import org.hibernate.SessionFactory; 15 import org.hibernate.Transaction; 16 import org.hibernate.cfg.Configuration; 17 import org.hibernate.service.ServiceRegistry; 18 import org.hibernate.service.ServiceRegistryBuilder; 19 import org.junit.After; 20 import org.junit.Before; 21 import org.junit.Test; 22  23 import com.yl.hibernate.entities.Department; 24 import com.yl.hibernate.entities.Employee; 25  26 public class HibernateTest { 27  28     private SessionFactory sessionFactory; 29     private Session session; 30     private Transaction transaction; 31      32     @Before 33     public void init() { 34         Configuration configuration = new Configuration().configure(); 35         ServiceRegistry serviceRegistry =  36                 new ServiceRegistryBuilder().applySettings(configuration.getProperties()) 37                                             .buildServiceRegistry(); 38  39         sessionFactory = configuration.buildSessionFactory(serviceRegistry); 40          41         session = sessionFactory.openSession(); 42  43         transaction = session.beginTransaction(); 44     } 45     @After 46     public void destory() { 47         transaction.commit(); 48          49         session.close(); 50          51         sessionFactory.close(); 52     } 53      54     @Test 55     public void testHQL() { 56         //1.创建 Query 对象 57         //基于位置参数 58         String hql = "FROM Employee e WHERE e.salary > ? AND e.email LIKE ? AND e.dept = ? ORDER BY e.salary"; 59         Query query = session.createQuery(hql); 60         //2.绑定参数 61         //Query 对象调用setXxx()方法支持方法链的编程风格 62         Department dept = new Department(); 63         dept.setId(30); 64         query.setFloat(0, 2000) 65              .setString(1, "%A%") 66              .setEntity(2, dept); 67         //3.执行查询 68         List<Employee> emps = query.list(); 69         System.out.println(emps); 70     } 71      72     @Test 73     public void testHQLNamedParameter() { 74         //1.创建 Query 对象 75         //基于命名参数 76         String hql = "FROM Employee e WHERE e.salary > :sal AND e.email LIKE :email"; 77         Query query = session.createQuery(hql); 78         //2.绑定参数 79         query.setFloat("sal", 2000) 80              .setString("email", "%A%"); 81         //3.执行查询 82         List<Employee> emps = query.list(); 83         System.out.println(emps.size()); 84     } 85     /** 86      * 分页查询 87      */ 88     @Test 89     public void testPageQuery() { 90         String hql = "FROM Employee"; 91         Query query = session.createQuery(hql); 92          93         int pageNo = 3; 94         int pageSize = 5; 95          96         List<Employee> employees = query.setFirstResult((pageNo-1) * pageSize) 97                                          .setMaxResults(pageSize) 98                                          .list(); 99         System.out.println(employees);100         101     }102     /**103      * 在映射文件中定义命名查询语句104      */105     @Test106     public void testNamedQuery() {107         Query query = session.getNamedQuery("salaryEmps");108         109         List<Employee> emps = query.setFloat("minSal", 2000)110                                     .setFloat("maxSal", 3000)111                                     .list();112         System.out.println(emps);113         114     }115     /**116      * 投影查询117      */118     @Test119     public void testFieldQuery() {120         String hql = "SELECT e.email, e.salary, e.dept FROM Employee e WHERE e.dept = :dept";121         Query query = session.createQuery(hql);122         123         Department dept = new Department();124         dept.setId(20);125         List<Object[]> result = query.setEntity("dept", dept).list();126         127         for (Object[] objects : result) {128             System.out.println(Arrays.asList(objects));129         }130         131     }132     133     /**134      * 投影查询135      */136     @Test137     public void testFieldQuery2() {138         String hql = "SELECT new Employee(e.email, e.salary, e.dept) "139                     + "FROM Employee e "140                     + "WHERE e.dept = :dept";141         142         Query query = session.createQuery(hql);143         144         Department dept = new Department();145         dept.setId(20);146         List<Employee> result = query.setEntity("dept", dept).list();147         148         for (Employee emp : result) {149             System.out.println(emp.getId() + ", " + emp.getEmail() + ", " + emp.getSalary() + ", " + emp.getDept());150         }151         152     }153     154     @Test155     public void testGroupBy() {156         String hql = "SELECT min(e.salary), max(e.salary) " 157                 + "FROM Employee e "158                 + "GROUP BY e.dept "159                 + "HAVING min(salary) > :minSal";160         Query query = session.createQuery(hql)161                              .setFloat("minSal", 700);162         163         List<Object[]> result = query.list();164         for (Object[] objects : result) {165             System.out.println(Arrays.asList(objects));166         }167     }168     /**169      * 迫切左外连接170      */171     @Test172     public void testLeftJoinFetch() {173         /*String hql = "SELECT DISTINCT d FROM Department d LEFT JOIN FETCH d.emps";174         Query query = session.createQuery(hql);175         176         List<Department> depts = query.list();177         System.out.println(depts.size());*/178         179         String hql = "FROM Department d LEFT JOIN FETCH d.emps";180         Query query = session.createQuery(hql);181         182         List<Department> depts = query.list();183         depts = new ArrayList<Department>(new LinkedHashSet<Department>(depts));184         185         System.out.println(depts.size());186         187         for (Department department : depts) {188             System.out.println(department.getName() + "-" + department.getEmps().size());189         }190     }191     192     @Test193     public void testLeftJoin() {194         /*String hql = "FROM Department d LEFT JOIN d.emps";195         Query query = session.createQuery(hql);196         197         List<Object[]> result = query.list();198         System.out.println(result);199         200         for (Object[] objects : result) {201             System.out.println(Arrays.asList(objects));202         }*/203         204         String hql = "SELECT DISTINCT d FROM Department d LEFT JOIN d.emps";205         Query query = session.createQuery(hql);206         207         List<Department> depts = query.list();208         System.out.println(depts.size());209         210         for (Department department : depts) {211             System.out.println(department.getName() + ", " + department.getEmps().size());212         }213     }214     215     @Test216     public void testInnerJoinFetch() {217         /*String hql = "SELECT DISTINCT d FROM Department d INNER JOIN FETCH d.emps";218         Query query = session.createQuery(hql);219         220         List<Department> depts = query.list();221         System.out.println(depts.size());*/222         223         String hql = "FROM Department d INNER JOIN FETCH d.emps";224         Query query = session.createQuery(hql);225         226         List<Department> depts = query.list();227         depts = new ArrayList<Department>(new LinkedHashSet<Department>(depts));228         229         System.out.println(depts.size());230         231         for (Department department : depts) {232             System.out.println(department.getName() + "-" + department.getEmps().size());233         }234     }235     236     @Test237     public void testInnerJoin() {238         /*String hql = "FROM Department d INNER JOIN d.emps";239         Query query = session.createQuery(hql);240         241         List<Object[]> result = query.list();242         System.out.println(result);243         244         for (Object[] objects : result) {245             System.out.println(Arrays.asList(objects));246         }*/247         248         String hql = "SELECT DISTINCT d FROM Department d INNER JOIN d.emps";249         Query query = session.createQuery(hql);250         251         List<Department> depts = query.list();252         System.out.println(depts.size());253         254         for (Department department : depts) {255             System.out.println(department.getName() + ", " + department.getEmps().size());256         }257     }258     259 }

 

Hibernate之HQL介绍