第 14 章 用 hibernate 检索数据

33
第 14 第 第 Hibernate 第第第第 • 第第第第第第第第第第第第第第第第第第 第第第第第第第 load() 第 g et() 第第第第第第第第第第 第第第第第第第第第第 ,。 Hibernate 第第第第第第第第第第第第第第第第第第HQL 第 第 第第第第第第第第第 第第第第第第Hibernate 第第第第第第第第第Query B y Criteria QBC 第第第第第第 )( Query By Ex ample QBE 第第第第第第第第 第第第第第第 )。 SQL 第 nat ive SQL 第第第第第 ), Hibernate 第第第第第第第第第r esult set 第第第第第第第第第 第第第第第第第第 )。 Hibernat e 第第第第第第第

Upload: tovi

Post on 16-Mar-2016

97 views

Category:

Documents


6 download

DESCRIPTION

第 14 章 用 Hibernate 检索数据. - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: 第 14 章  用 Hibernate 检索数据

第 14 章 用 Hibernate 检索数据• 如果不知道所要寻找的对象的持久化标识,那么就无法通过 load() 或 get() 函数来获取持久化对象,这里就需要使用查询。 Hibernate 支持强大且易于使用的面向对象查询语言( HQL )。如果希望通过编程的方式创建查询, Hibernate 提供了完善的按条件( Query By Criteria , QBC )以及按样例( Query By Example , QBE )进行查询的功能。也可以用本地 SQL ( native SQL )描述查询, Hibernate 额外提供了将结果集( result set )转化为对象的支持。本章将详细介绍在 Hibernate 中如何查询数据

Page 2: 第 14 章  用 Hibernate 检索数据

14.1 查询基础• 序言中提到的几种查询方式虽然方法各有不同,但基本的操作顺序都是一样的,都需要准备查询条件、执行查询操作、处理查询结果。不同的方法需要选择不同的工具类,在个别情况下也可以混用。

Page 3: 第 14 章  用 Hibernate 检索数据

14.1.1 执行查询• HQL 和本地 SQL(native SQL) 查询要通过为 org.hibernate.Query 的实例来表达。这个接口提供了参数绑定、结果集处理以及运行实际查询的方法。总是可以通过当前 Session 获取一个 Query对象,如代码 14-1 所示,列出了几种使用 Quey来执行查询的例子:• 这里提前介绍一下什么是 HQL ? HQL 是 HibernateQuery Language 的缩写, HQL 的语法很像SQL 的语法,但 HQL 是一种面向对象的查询语言。因此, SQL 的操作对象是数据表和列等数据对象,而 HQL 的操作对象是类、实例、属性等。下一节将详细介绍它。

Page 4: 第 14 章  用 Hibernate 检索数据

14.1.2 用 iterate() 方法迭代查询结果• 在某些情况下,可以使用 iterate() 方法得到更好的性能。这通常是预期返回的结果在 session ,或二级缓存 (second-level cache) 中已经存在时的情况。如若不然, iterate() 会比 list() 慢,而且可能简单查询也需要进行多次数据库访问: iterate() 会首先使用 1 条语句得到所有对象的持久化标识 (identifiers) ,再根据持久化标识执行多条附加的 select 语句实例化实际的对象。

Page 5: 第 14 章  用 Hibernate 检索数据

14.1.3 指定绑定参数• 除了 JDBC 风格的问号 (?) 接收参数外,接口 Query 还提供了一种对命名参数 (named parameters) 参数进行绑定的方法。命名参数 (named parameters) 在查询字符串中是形如: name 的标识符。如果按 JDBC 绑定参数, Hibernate 对参数从 0 开始计数。• 如代码 14-3 所示,给出了按顺序绑定参数和按名称绑定参数的例子。两者方法相同都是 setString() 或 setInterger() ,但方法的第一个参数不同,一个是整数表示顺序,另一个是 String 类型表示名称。

Page 6: 第 14 章  用 Hibernate 检索数据

14.1.4 用 Hibernate 简单分页• 如果需要指定结果集的范围(希望返回的最大行数 / 或开始的行数),应该使用 Query 接口提供的方法:• Query q = sess.createQuery("from DomesticPerson person");• q.setFirstResult(20);• q.setMaxResults(10);• List persons = q.list();

Page 7: 第 14 章  用 Hibernate 检索数据

14.1.5 可滚动遍历 (Scrollable iteration)• 如果当前使用 JDBC 驱动支持可滚动的结果集( JDBC2.0 后一般的主流数据库驱动都支持可滚动结果集), Query 接口还可以使用 ScrollableResults ,允许用户在查询结果中上下移动游标, • 注意:使用此功能需要保持数据库连接(以及游标 (cursor) )处于一直打开状态。如果需要断开连接使用分页功能,请使用 setMaxResult()/setFirstResult() 。

Page 8: 第 14 章  用 Hibernate 检索数据

14.2 HQL 语句详解• HQL 的概念在本章的一开始就做过介绍,它是 Hibernate 专用的查询语言,语法与 SQL 类似,但操作的目标是对象。 HQL 是完全面向对象的查询语言,因此可以支持继承和多态等特征。

Page 9: 第 14 章  用 Hibernate 检索数据

14.2.1 HQL 基础• HQL 查询依赖于 Query 类,每个 Query 实例对应一个查询对象。使用 HQL 查询可按如下步骤进行:• ( 1 )获取 HibernateSession 对象;• ( 2 )编写 HQL 语句;• ( 3 )以 HQL 语句作为参数,调用 Session 的 createQuery 方法创建查询对象;• ( 4 )如果 HQL 语句包含参数,调用 Query 的setXxx 方法为参数赋值;• ( 5 )调用 Query 对象的 list 等方法遍历查询结果。

Page 10: 第 14 章  用 Hibernate 检索数据

14.2.2 用 from 子句指定数据表• from 子句是最简单的 HQL 语句,也是最基本的HQL 语句。 from 关键字后紧跟持久化类的类名。例如:• from Person• 表明从 Person 持久化类中选出全部的实例。大部分时候,推荐为该 Person 的每个实例起别名。例如:• from Person as p

Page 11: 第 14 章  用 Hibernate 检索数据

14.2.3 select 子句查询数据• select 子句虽然不是必须的(在 SQL 中 select 是必须的),但其作用非常重要,主要有以下几种用法:• ( 1 )查询单个属性。 select 子句用于确定选择出的属性,当然 select 选择的属性必须是 from 后持久化类包含的属性。例如: select p.name from Person as p• ( 2 )查询组件中的属性。 select 可以选择任意属性,不仅可以选择持久化类的直接属性,还可以选择组件属性包含的属性,例如: select p.name.firstName from Person as p• ( 3 )查询多个属性。查询语句可以返回多个对象和(或)属性,存放在 Object[] 队列中,例如: select p.name , p.address from Person as p

Page 12: 第 14 章  用 Hibernate 检索数据

14.2.3 select 子句查询数据• ( 4 )把多个属性封装成一个 list 。 select 也支持将选择出的属性存入一个 List 对象中,例如: select new list(p.name , p.address) from Person as p• ( 5 )封装成对象。甚至可以将选择出的属性直接封装成对象,例如: select new ClassTest(p.name , p.address) from Person as p• 前提是 ClassTest 支持 p.name 和 p.address 的构造器,假如 p.name 的数据类型是 String , p.address 的数据类型是 String ,则 ClassTest 必须有如下的构造器: ClassTest(String s1 , String s2)• ( 6 )封装为 map 。 select 还支持给选中的表达式命名别名,例如: select p.name as personName from Person as p

Page 13: 第 14 章  用 Hibernate 检索数据

14.2.4 HQL 中的聚集函数• HQL 也支持在选出的属性上,使用聚集函数。 HQL 支持的聚集函数与 SQL 完全相同,有如下 5 个:• avg ,计算属性平均值。• count ,统计选择对象的数量。• max ,统计属性值的最大值• min ,统计属性值的最小值。• sum ,计算属性值的总和。

Page 14: 第 14 章  用 Hibernate 检索数据

14.2.5 多态查询• 关于多态已经在“复杂映射关系”一章中“继承关系映射”有过详细介绍。 HQL 查询语句被设计成能理解多态查询, from 后跟的持久化类名,不仅会查询出该持久化类的全部实例,还会查询出该类的子类的全部实例。如下面的查询语句:• from Person as p• 该查询语句不仅会查询出 Person 的全部实例,还会查询出 Person 的子类,如 Manger 、 Employee 、 Customer 的全部实例,前提是 Person和 Manger 、 Employee 、 Customer 这些子类完成了正确的继承映射。

Page 15: 第 14 章  用 Hibernate 检索数据

14.2.6 用 where 子句添加查询条件• where 子句用于筛选选中的结果,缩小选择的范围。如果没有为持久化实例命名别名,可以直接使用属性名引用属性。如下面的 HQL 查询语句:• from Person where name like 'tom%'• 如果为持久化实例命名了别名,则应该使用完整的属性名。• from Person as p where p.name like "tom%"• 复合属性表达式加强了 where 子句的功能,例如如下 HQL 查询语句:• from Person p where p.address.country like "us%"

Page 16: 第 14 章  用 Hibernate 检索数据

14.2.7 查询条件中的表达式• HQL 的功能非常丰富, where 子句后支持的运算符异常丰富,不仅包括 SQL 的运算符,还包括EJB-QL 的运算符等。 where 子句中允许使用大部分 SQL 支持的表达式:• 数学运算符 + 、–、 * 、 / 等。• 二进制比较运算符 = 、 >= 、 <= 、 <> 、 != 、 like 等。• 逻辑运算符 and 、 or 、 not 等。• in 、 not in 、 between 、 is null 、 is not null 、is empty 、 is not empty 、 member of 和 not member of 等。

Page 17: 第 14 章  用 Hibernate 检索数据

14.2.8 用 order by 子句排序• 查询返回的列表 (list) 可以根据类或组件属性的任何属性进行排序,例如:• from Person as p• order by p.name , p.age• 还可使用 asc 或 desc 关键字指定升序或降序的排序规则,例如:• from Person as p• order by p.name asc , p.age desc• 如果没有指定排序规则,默认采用升序规则。即是否使用 asc 关键字是没有区别的,加 asc 是升序排序,不加 asc 也是升序排序。

Page 18: 第 14 章  用 Hibernate 检索数据

14.2.9 用 group by 子句分组• 返回聚集值的查询可以对持久化类或组件属性的属性进行分组,分组所使用的 group by 子句。看下面的 HQL 查询语句:• select person.age , sum(person.weight) , count(person)• from Person person• group by person. age

Page 19: 第 14 章  用 Hibernate 检索数据

14.2.10 HQL 的子查询• 如果底层数据库支持子查询,则可以在 HQL 语句中使用子查询。与 SQL 中子查询相似的是, HQL 中的子查询也需要使用 () 括起来。如:• from Person as fatPerson• where fatPerson.weight >( select avg(person.weight) from Manager person )• 如果 select 中包含多个属性,则应该使用元组构造符:• from Person as p• where not ( p.name , p.age ) in (• select m.name , m.age from Manger m• )

Page 20: 第 14 章  用 Hibernate 检索数据

14.2.11 用 fetch 关键字来延时加载集合• 对于集合属性, Hibernate 默认采用延迟加载策略。例如,对于持久化类 Person ,有集合属性 scores 。加载 Person 实例时,默认不加载 scores 属性。如果 Session 被关闭, Person 实例将无法访问关联的 scores 属性。• 为了解决该问题,可以在 Hibernate 映射文件中取消延迟加载或使用 fetch join ,例如:• from Person as p join p.scores

Page 21: 第 14 章  用 Hibernate 检索数据

14.2.12 HQL 语句放入配置文件中• HQL 查询还支持将查询所用的 HQL 语句放入配置文件中,而不是代码中。通过这种方式,可以大大提供程序的解耦。使用 query 元素定义命名查询,在 mapping 文件中与 class 元素是并列关系。

Page 22: 第 14 章  用 Hibernate 检索数据

14.3 条件查询• HQL 极为强大,但是有些人希望能够动态的使用一种面向对象 API 创建查询,而非在他们的 Java代码中嵌入字符串。对于那部分人来说, Hibernate 提供了直观的 Criteria 查询 API , Query By Criteria 简称 QBC 。

Page 23: 第 14 章  用 Hibernate 检索数据

14.3.1 添加查询条件• 一个单独的查询条件是 org.hibernate.criterion.Criterion接口的一个实例。 Hibernate 提供了一个工具类 --org.hibernate.criterion.Restrictions ,它定义了获得某些内置 Criterion 类型的工厂方法,来构造 Restrictions 对象,如:• // 添加查询条件• List persons = sess.createCriteria(Person.class)• .add( Restrictions.like("name" , "Fritz%") )• .add( Restrictions.between("weight" , minWeight , maxWeight) )• .list();

Page 24: 第 14 章  用 Hibernate 检索数据

14.3.2 结果集排序• 可以使用 org.hibernate.criterion.Order 来为查询结果排序,而不是去拼凑 order by 字符串。 Order 类同样提供了工厂方法来构建,另一种方式是通过 Property 类构建,如下代码两种方式都提供了:• // 工厂方法来构建 Order 类• List persons = sess.createCriteria(Person.class)• .add( Restrictions.like("name" , "F%")• .addOrder( Order.asc("name") )• .addOrder( Order.desc("age") )• .setMaxResults(50)• .list();• //Property 类构建 Order 类• List persons = sess.createCriteria(Person.class)• .add( Property.forName("name").like("F%") )• .addOrder( Property.forName("name").asc() )• .addOrder( Property.forName("age").desc() )• .setMaxResults(50)• .list();

Page 25: 第 14 章  用 Hibernate 检索数据

14.3.3 条件查询中的关联关系• 可以使用 createCriteria() 非常容易的在互相关联的实体间建立约束。• // 使用 createCriteria 建立实体间的约束• List persons = sess.createCriteria(Person.class)• .add( Restrictions.like("name" , "F%") )• .createCriteria("parts")• .add( Restrictions.like("name" , "F%") )• .list();

Page 26: 第 14 章  用 Hibernate 检索数据

14.3.4 使用样例查询• 样例查询顾名思义就是一个一个样例作为条件,把与这个样例有相同属性的实例查询出来。 Hibernate 提供了 org.hibernate.criterion.Example类,允许用户通过一个给定实例来构建一个条件查询。如下代码,构造一个 person 实例作为查询条件,此时版本属性、标识符和关联被忽略。默认情况下值为 null 的属性将被排除。

Page 27: 第 14 章  用 Hibernate 检索数据

14.3.5 离线 (detached) 查询和子查询• Hibernate3 提供了一个新的 Criteria : DetachdCriteria 。此类可脱离 Session 实例而存在。这样就可以将某些通用的 Criteria 查询条件进行抽离,每次使用前再与当前的 Session 绑定以获得更好的代码重用效果。• 典型应用如下: DetachedCriteria 类使在一个 session 范围之外创建一个查询,并且可以使用任意的 Session 来执行它。

Page 28: 第 14 章  用 Hibernate 检索数据

14.4 直接使用 SQL• Hibernate 还支持使用 SQL 查询,使用 SQL 查询可以利用某些数据库的特性,或者用于将原有的 JDBC 应用迁移到 Hibernate 应用上。使用命名的 SQL 查询还可以将 SQL 语句放在配置文件中配置,从而提高程序的解耦,命名 SQL 查询还可以用于调用存储过程。如果是一个新的应用,通常不要使用 SQL 查询。

Page 29: 第 14 章  用 Hibernate 检索数据

14.4.1 使用 SQL 查询• SQL 查询是通过 SQLQuery 接口来表示的, SQLQuery 接口是 Query 接口的子接口,因此完全可以调用 Query 接口的方法:• setFirstResult() ,设置返回结果集的起始点。• setMaxResults() ,设置查询获取的最大记录数。• list() ,返回查询到的结果集。• 但 SQLQuery 比 Query 多了两个重载的方法:• addEntity ,将查询到的记录与特定的实体关联。• addScalar ,将查询的记录关联成标量值。

Page 30: 第 14 章  用 Hibernate 检索数据

14.4.2 SQL 语句放入配置文件中• 可以在映射文档中定义查询的名字,然后就可以象调用一个命名的 HQL 查询一样直接调用命名 SQL 查询。在文件中的 SQL 语句,使用 <sql-query> 标签,同样与映射文件中的 class 同一个级别,还有两个元素 <return-join> 和 <load-collection> 。它们是用来连接关联以及将查询定义为预先初始化各个集合的

Page 31: 第 14 章  用 Hibernate 检索数据

14.4.3 调用存储过程• Hibernate3 引入了对存储过程查询 (stored procedure) 和函数 (function) 的支持。要求这个存储过程或者函数必须返回一个结果集,作为 Hibernate 能够使用的第一个外部参数。因为存储过程本身完成了查询的全部操作,所以调用存储过程进行的查询无法使用 setFirstResult()/setMaxResults() 进行分页。• 存储过程只能返回一个结果集,如果存储过程返回多个结果集, Hibernate 将仅处理第一个结果集,其他将被丢弃。• 如果在存储过程里设定 SET NOCOUNT ON ,将有更好的性能表现。当然也可以没有该设定。

Page 32: 第 14 章  用 Hibernate 检索数据

14.5 数据过滤• 数据过滤不是一种常规的数据查询方法,而是一种整体的筛选方法。数据过滤也可对数据进行筛选,因此,将其放在 Hibernate 的数据查询框架中介绍。如果一旦启用了数据过滤器,则不管数据查询,还是数据加载,该过滤器将自动作用于所有数据,只有满足过滤条件的记录才会被选出来。• 过滤器与定义在类和集合映射文件上的“ where” 属性非常相似。它们的区别是过滤器可以带参数,应用程序可以在运行时决定是否启用指定的过滤器,以及使用什么样的参数值。而映射文件上的“ where” 属性将一直生效,且无法动态传入参数。过滤器的用法很像数据库视图,区别是视图在数据库中已经定义完成,而过滤器则还需在应用程序中确定参数值。

Page 33: 第 14 章  用 Hibernate 检索数据

14.6 小结• 数据的检索是数据库最重要的功能之一。在本章中介绍了几种 Hibernate 检索数据的方法。在实际应用中可根据需求灵活应用,除非必须应该尽量避免直接使用 SQL 语句,这将违背 Hibernate的设计初衷,为将来数据库移植也带来隐患。