05_Hibernate ------检索方式

5 检索方式

 

  1. 概述

Hibernate提供了以下几种检索对象的方式

OID检索方式:按照对象的OID来检索对象get/load

对象图导航检索方式:根据已经加载的对象导航到其他对象

         order.getCustomer().getCustomerName();

HQL检索方式:使用面向对象的HQL(Hibernate Query Language)查询语言

         Query

QBC检索方式:使用QBC(Query By Criteria) API来检索对象。这种API封装了基于字符串形式的查询语句,提供了更加面向对象的查询接口。

●本地SQL检索方式:使用本地数据库的SQL查询语句。

         SQLQuery extends Query

 

  1. HQL
    1. 概述  

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

  1. 以面向对象的方式查询数据库表 
  2. 在查询语句中设定各种查询条件
  3. 支持投影查询,即仅检索出对象的部分属性
  4. 支持分页查询
  5. 支持连接查询
  6. 支持分组查询,允许使用HAVING和GROUP BY关键字
  7. 提供内置聚集函数,如sum(),min()和max(),avg(),count()等
  8. 支持子查询
  9. 支持动态绑定参数
    1. FROM子句

在SQL中,FROM子句是用于指定要查询的数据库表,在HQL中,替换为与数据库表对应的Java实体类即可。

例如:

SQL

SELECT * FROM EMPS

HQL

FROM Employee

此时HQL语句将查询数据库表中的所有字段,并自动注入到对应实体类对象的对应属性中。

同时需要说明的是:HQL语句中FROM等关键字不区分大小写,但Java类的类名严格区分大小写。

 

    1. 执行HQL查询语句

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

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

 

           //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);

          }

 

 

    1. 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对象的引用。

 

    1. 使用基于位置的占位符参数

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

HQL

FROM Employee e WHERE e.salary>?

 

填充占位符

query.setDouble(0, 8000.00);

 

    1. 使用具名参数

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

具名参数的格式是:“:参数名称”。

例如:

HQL

FROM Employee e WHERE e.salary>:salaryParam

 

填充占位符

query.setDouble( "salaryParam", 9000);

 

    1. 以实体类对象作为参数

对于已经通过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会自动按照关联关系中规定的主外键关系进行查询。

 

    1. ORDER BY子句

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

HQL

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

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

 

    1. 分页查询

分页查询是HQL的一大亮点,不必关心底层数据库的具体实现是什么,使用HQL调用固定的方法就能够实现垮数据库平台的分页查询。

在分页时我们需要指定两个最基本的数据,一个是当前页的页码:pageNo,一个是每页显示多少条数据:pageSize。

下表列出了Query接口中与分页相关的两个函数

函数名

作用

setFirstResult(int index)

指定查询结果从index位置开始取,index从0开始

setMaxResults(int maxResults)

指定查询结果取maxResults条数据

 

index和pageNo的关系是:index=(pageNo-1)*pageSize(pageNo:当前页的页码; pageSize:每页显示数据的数量)

 

具体操作方法是:

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

                      .setMaxResults(pageSize)

                      .list();

 

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

 

    1. 投影查询方式一

所谓投影查询其实就是仅查询实体类对象的部分字段,这里用到了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]);

          }

 

    1. 投影查询方式二

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

HQL

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

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

 

    1. 多表查询

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

 

使用distinct去重

String hql = “select distinct d From Department d left join fetch d.empSet”;

 

    1. 报表查询

和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数组中。

 

    1. 子查询

子查询是SQL语句中非常重要的功能,它可以在SQL语句中利用另外一条SQL语句的查询结果。HQL同样对子查询功能提供了支持。与SQL子查询不同的是,HQL不支持在FROM子句中使用子查询。

例如:查询员工数量大于5的部门

HQL

From Department d where (select count(empSet) From d.empSet empSet)>5

 

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

HQL

select e.empName,e.department.deptName

from Employee e

where e.department in

          (From Department d where d.deptName like 'A%')

 

    1. 删除数据

HQL

Delete From Employee e WHERE e.empId=117

 

session.createQuery(queryString).executeUpdate()

 

    1. 更新数据

HQL

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

 

session.createQuery(queryString).executeUpdate()

 

 

  1. QBC
    1. 概述

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

 

    1. 创建Criteria对象

创建Criteria对象是进行QBC查询的第一步,类似于HQL查询中创建Query对象,只不过Criteria对象和Query对象的用法差别很大。

Criteria对象可以通过session对象的createCriteria()方法创建,创建时需要提供目标持久化类的Class类对象(即目标持久化类的运行时类)

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

 

    1. 取得查询结果

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

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

List<Employee> list = criteria.list();

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

 

    1. 封装查询条件

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()方法也支持连缀调用。

 

    1. 使用AND和OR连接查询条件

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

Conjunction:AND连接,结合

Disjunction: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);

 

    1. 报表查询

在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();

 

 

    1. QBC排序

Order asc = Order.asc("salary");

Order desc = Order.desc("empName");

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

                                 .addOrder(asc)

                                 .addOrder(desc)

                                 .list();

 

    1. QBC分页

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

int pageNo = 2;

int pageSize = 5;

      

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

                         .setFirstResult((pageNo - 1)*pageSize)

                         .setMaxResults(pageSize)

                         .list();

 

  1. 执行本地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()

 

 

猜你喜欢

转载自blog.csdn.net/SSM_spring/article/details/90142405