1 / 33

第 14 章 用 Hibernate 检索数据

第 14 章 用 Hibernate 检索数据.

tovi
Download Presentation

第 14 章 用 Hibernate 检索数据

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


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

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

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

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

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

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

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

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

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

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

  11. 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

  12. 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

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

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

  15. 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%"

  16. 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 等。

  17. 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 也是升序排序。

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

  19. 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 • )

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

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

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

  23. 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();

  24. 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();

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

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

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

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

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

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

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

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

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

More Related