Hibernate 检索方式

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

2 HQL
2.1 概述
HQL(Hibernate Query Language)是面向对象的查询语言,它和SQL查询语言有些相似。在Hibernate提供的各种检索方式中,HQL是使用最广的一种检索方式。它有如下特点:
 以面向对象的方式查询数据库表
 在查询语句中设定各种查询条件
 支持投影查询,即仅检索出对象的部分属性
 支持分页查询
 支持连接查询
 支持分组查询,允许使用HAVING和GROUP BY关键字
 提供内置聚集函数,如sum(),min()和max()等
 支持子查询
 支持动态绑定参数
2.2 FROM子句
在SQL中,FROM子句是用于指定要查询的数据库表,在HQL中,替换为与数据库表对应的Java实体类即可。
例如:

SQL SELECT * FROM EMPS
HQL FROM Employee

此时HQL语句将查询数据库表中的所有字段,并自动注入到对应实体类对象的对应属性中。
同时需要说明的是:HQL语句中FROM等关键字不区分大小写,但Java类的类名严格区分大小写。

2.3 执行HQL查询语句
在Hibernate中,HQL语句由Query对象执行,Query对象可以通过Session对象获取。

    //1.通过session对象创建Query对象
          String hql = "FROM Employee";
          Query query = session.createQuery(hql);

           //2.调用Query对象的方法获取查询结果
           //结果集中有多条记录:list()
           //结果集中只有一条记录:uniqueResult()
          List<Employee> list = query.list();
           for (Employee employee : list) {
              System. out.println(employee);
          }

2.4 WHERE子句
和SQL的语法一样,HQL中的WHERE子句也用来指定查询条件。只不过这里指定查询条件使用的不是数据库表的字段,而是Java类的属性。
例如:

SQL SELECT * FROM EMPS WHERE EMPS.SALARY>5000
HQL     FROM Employee e WHERE e.salary>5000

这里Employee e的语法非常像Java中声明一个Employee类型的变量:e。其实也确实可以这样理解——使用e作为Employee对象的引用。

2.5 使用基于位置的占位符参数
将上例中的具体值使用占位符“?”代替,并调用Query对象的setXxx()方法按照参数的不同类型动态填充即可,需要注意的是和JDBC中的PreparedStatement接口不同,这里占位符的索引从0开始。

HQL FROM Employee e WHERE e.salary>?

填充占位符 query.setDouble(0, 8000);

2.6 使用具名参数
在HQL中不但能够使用基于位置的占位符参数,还能够使用基于名称的具名参数,使用具名参数的好处是不必关心当前参数的索引值。
具名参数的格式是:“:参数名称”。
例如:

HQL FROM Employee e WHERE e.salary>:salaryParam
填充占位符   query.setDouble( "salaryParam", 9000);

2.7 以实体类对象作为参数
对于已经通过Hibernate关联关系映射建立了关联关系的实体类,HQL还支持直接使用实体类对象本身作为参数值。
例如:Employee和Department之间建立了单向(或双向)多对一关联关系,Employee类中使用department属性关联Department类的对象,那么HQL语句可以为:

HQL from Employee e where e.department=?
这里填充占位符可以使用一个Department对象:
Department department = new Department();
department.setDeptId(5);

填充占位符   query.setEntity(0, department)

Hibernate会自动按照关联关系中规定的主外键关系进行查询。

2.8 ORDER BY子句
使用ORDER BY子句可以进行排序

HQL FROM Employee e WHERE e.salary>:salaryParam ORDER BY e.salary DESC

和SQL一样,默认按照升序排列。DESC表示降序,ASC表示升序。

2.9 分页查询
分页查询是HQL的一大亮点,不必关心底层数据库的具体实现是什么,使用HQL调用固定的方法就能够实现垮数据库平台的分页查询。
在分页时我们需要指定两个最基本的数据,一个是当前页的页码:pageNo,一个是每页显示多少条数据:pageSize。
下表列出了Query接口中与分页相关的两个函数
函数名————作用
setFirstResult(int index)——指定查询结果从index位置开始取,index从0开始
setMaxResults(int maxResults)——指定查询结果取maxResults条数据

index和pageNo的关系是:index=(pageNo-1)*pageSize

具体操作方法是:

List<Employee> list = query.setFirstResult((pageNo - 1)*pageSize)
                      .setMaxResults(pageSize)
                      .list();

这里我们使用了连缀的方式调用Query对象的API,之所以能够实现连缀是因为每个方法的返回值都仍然是Query对象本身。

2.10 投影查询方式一
所谓投影查询其实就是仅查询实体类对象的部分字段,这里用到了HQL语句的SELECT关键词。

HQL SELECT e.empName,e.salary From Employee e WHERE e.salary>9000

那么此时的查询结果以什么形式返回呢?HQL并没有将使用空的Employee对象接收empName和salary的值,而是把它们放在了一个Object数组中。

      Query query = session.createQuery(queryString);
          List<Object[]> list = query.list();
          for (Object[] objects : list) {
              System. out.println(objects[0]+" "+objects[1]);
          }

2.11 投影查询方式二
接收投影查询结果可以仍然使用实体类的对象,但要求实体类中提供对应的构造器。

HQL SELECT new Employee(e.empName,e.salary) From Employee e

这样得到的每一条数据都将被封装到Employee对象中。

2.12 多表查询
HQL支持使用外连接、内连接等方式进行连表查询,甚至支持使用FETCH关键字进行“迫切”连接查询。
①迫切左外连接

HQL From Department d LEFT JOIN FETCH d.empSet

这里使用LEFT JOIN表示进行“左外连接”查询,生成的SQL语句将查询关联的Employee类对应的全部数据,所以Employee的数据既然查询得到了,那么就应该将它们设置到Department对象的empSet属性中,否则这个已经执行了的操作就浪费了。而是否对empSet属性进行设置就看是否包含了FETCH关键字,包含就设置,不包含就不设置,这就是“迫切”的含义。
②迫切内连接

HQL From Department d INNER JOIN FETCH d.empSet

2.13 报表查询
和SQL一样,HQL也使用GROUP BY和HAVING子句配合起来进行分组,再结合统计函数进行报表查询。

HQL SELECT min(e.salary),max(e.salary) 
From Employee e 
GROUP BY e.department 
HAVING min(e.salary)>3000

min()和max()统计函数的结果最终被放在了一个Object数组中。

2.14 子查询
子查询是SQL语句中非常重要的功能,它可以在SQL语句中利用另外一条SQL语句的查询结果。HQL同样对子查询功能提供了支持。与SQL子查询不同的是,HQL不支持在FROM子句中使用子查询。
例如:查询员工数量大于5的部门

HQL From Department d where (select count(emp) From d.empSet emp)>4

查询部门名以“A”开头的部门的员工姓名和部门名称

HQL select e.empName,e.department.deptName 
from Employee e 
where e.department in 
     (From Department d where d.deptName like 'A%')

2.15 删除数据

HQL Delete From Employee e WHERE e.empId=117

session.createQuery(queryString).executeUpdate()

2.16 更新数据

HQL UPDATE Employee e Set e.empName=’Tom’ WHERE e.empId=115

session.createQuery(queryString).executeUpdate()

3 QBC
3.1 概述
QBC查询就是通过使用Hibernate提供的Query By Criteria API来查询对象,这种API 封装了SQL语句的动态拼装,对查询提供了更加面向对象的功能接口。

3.2 创建Criteria对象
创建Criteria对象是进行QBC查询的第一步,类似于HQL查询中创建Query对象,只不过Criteria对象和Query对象的用法差别很大。
Criteria对象可以通过session对象的createCriteria()方法创建,创建时需要提供目标持久化类的Class类对象。

Criteria criteria = session.createCriteria(Employee.class);

3.3 取得查询结果
Criteria对象大体上有两种方式获取查询结果:list()方法和uniqueResult()方法。list()方法获取多条记录的查询结果,uniqueResult()方法获取单一记录的查询结果。

Criteria criteria = session.createCriteria(Employee.class);
List<Employee> list = criteria.list();

这个例子表示不带任何查询条件,查询全部Employee对象,并返回全部Employee对象组成的List集合。

3.4 封装查询条件
QBC查询最大的特点是可以将SQL语句中的查询条件以面向对象的方式封装起来,并根据封装好的查询条件返回结果。
封装查询条件要用到Restrictions类的各个静态方法。
方法名 示例 对应SQL

eq(String propertyName, Object value)   eq(“salary”,5000.00);   where salary=5000.00
like(String propertyName, Object value) like(“empName”,”%a%”);  where emp_name like ‘%a%’
gt(String propertyName, Object value)   gt(“salary”,300);   where salary>300
lt(String propertyName, Object value)   lt(“salary”,300);   where salary<300
le(String propertyName, Object value)   le(“salary”,300);   where salary<=300
ge(String propertyName, Object value)   ge(“salary”,300);   where salary>=300
between(String propertyName, Object lo, Object hi)  between(“salary”,300,500);  where salary between 300 and 500
in(String propertyName, Object[] values)    in(“salary”,[300,500,600]); where salary in (300,500,600)

封装查询条件之后,上述静态方法都会返回一个Criterion接口的实例,拿到这个Criterion对象后可以将其添加到Criteria对象中。例如:

Criterion like = Restrictions.like("empName","%a%");
Criterion gt = Restrictions.gt("salary",9000.00);
List<Employee> list = criteria
                         .add(like)
                         .add(gt)
                         .list();

显然add()方法也支持连缀调用。

3.5 使用AND和OR连接查询条件
在QBC API中使用Conjunction类表示AND,使用Disjunction表示OR,它们都可以连接Criterion对象生成AND或OR语句。

Criterion like = Restrictions. like("empName", "%a%");

Criterion gt = Restrictions. gt("salary", 9000.00);

//创建AND条件对象
Conjunction conjunction = Restrictions.conjunction();

//使用AND连接like和 gt
conjunction.add(like).add(gt);

List<Employee> list = session.createCriteria(Employee.class)
                                            .add(conjunction)
                                            .list();


Criterion like = Restrictions. like("empName", "%a%");

Criterion gt = Restrictions. gt("salary", 9000.00);

//创建OR条件对象
Disjunction disjunction = Restrictions.disjunction();

//使用OR对象将两个条件连接起来
disjunction.add(like).add(gt);

List<Employee> list = session.createCriteria(Employee.class)
                              .add( disjunction)
                              .list() ;

甚至AND和OR作为整体也可以连接在一起

Conjunction conjunction01 = Restrictions.conjunction();
Conjunction conjunction02 = Restrictions.conjunction();
Disjunction disjunction = Restrictions.disjunction();
disjunction.add(conjunction01).add(conjunction02);

3.6 报表查询
在QBC查询中可以使用Projections类的静态方法封装SQL中的统计函数。

AggregateProjection max = Projections.max("salary");
criteria.setProjection(max);

如果有多个统计函数需要执行,则创建ProjectionList对象,用于包含多个Projection对象

AggregateProjection max = Projections.max("salary");
AggregateProjection min = Projections.min("salary");
ProjectionList projectionList = Projections.projectionList();
projectionList.add(max).add(min);
List<Object[]> list = session.createCriteria(Employee.class)
                   .setProjection(projectionList)
                   .list();

可以使用groupProperty(String propertyName)方法对查询结果进行分组

Criteria criteria = session.createCriteria(Employee.class);

PropertyProjection groupProperty = Projections.groupProperty("department");

criteria.setProjection(groupProperty).list();

3.7 QBC排序

Order asc = Order.asc("salary");
Order desc = Order.desc("empName");
List<Employee> list = session.createCriteria(Employee.class)
                                     .addOrder(asc)
                                     .addOrder(desc)
                                     .list();

3.8 QBC分页
QBC分页和HQL分页的操作大体上是一致的。

int pageNo = 2;
int pageSize = 5;

List<Employee> list = session.createCriteria(Employee.class)
                            .setFirstResult((pageNo - 1)*pageSize)
                            .setMaxResults(pageSize)
                            .list();

4 执行本地SQL
有些情况下我们需要直接执行原始的SQL语句,这时可以使用session对象创建SQLQuery对象,并调用list()或uniqueResult()方法返回查询结果,如果是执行增删改操作,可以调用executeUpdate()方法。
创建SQL语句

String sql = "SELECT `EMP_ID`,`emp_name`,`SALARY`,`birthday`,`TELEPHONE`,`dept_id_fk` FROM `emps` WHERE `EMP_ID`=8";

创建SQLQuery对象

SQLQuery query = session.createSQLQuery(sql);

返回查询结果

Object[] object = (Object[]) query.uniqueResult()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值