现在的位置: 首页 > 综合 > 正文

Hibernate 中HQL语句

2013年02月15日 ⁄ 综合 ⁄ 共 13308字 ⁄ 字号 评论关闭

1.1 HQL基础 2

1.1.1 默认数据库表和数据 2

1.1.2 检索类的所有对象 4

1.1.3 检索类的某几个属性 5

1.1.4 指定别名 5

1.1.5 where条件子句 5

1.1.6 使用distinct过滤掉重复值 6

1.1.7 删除对象 6

1.1.8 更新对象值 7

1.1.9 查询计算属性值 7

1.1.10 使用函数 8

1.1.11 between...and...not between... and...确定查询范围 8

1.1.12 innot in确定查询集合 8

1.1.13 like进行模糊查询 8

1.1.14 and逻辑与 9

1.1.15 or逻辑或 9

1.1.16 order by对结果进行排序 10

1.1.17 group by对记录进行分组 10

1.1.18 having关键字 11

1.1.19 聚集函数 11

1.2 HQL进阶 12

1.2.1 查询类及其所有继承的类的实例 12

1.2.2 限制每次查询的返回对象数 12

1.2.3 绑定参数 14

1.2.4 在映射文件配置HQL语句 15

1.3 HQL的嵌套子查询 15

1.3.1 嵌套子查询的概念 15

1.3.2 带有IN谓词的子查询 16

1.3.3 比较子查询 16

1.3.4 带有ANYALL的子查询
17

1.4 HQL的多表查询 17

1.4.1 表之间的关联关系 17

1.4.2 表中的数据 18

1.4.3 修改持久化类 19

1.4.4 在映射文件中加入关联信息 20

1.4.5 左外连接 21

1.4.6 左外抓取连接 23

1.4.7 右外连接 24

1.4.8 内连接 24

1.4.9 抓取内连接 25

Hibernate HQL语句

本章介绍了Hibernate的几种主要检索方式:HQL检索方式、QBC检索方式、SQL检索方式。HQLHibernate Query Language的缩写,是官方推荐的查询语言。QBCQuery By Criteria的缩写,是Hibernate提供的一个查询接口。Hibernate是一个轻量级的框架,它允许使用原始SQL语句查询数据库。

1.1 HQL基础

HQLHiberante官方推荐的Hibernate检索方式,它使用类似SQL的查询语言,以面向对象的方式从数据库中查询。可以使用HQL查询具有继承、多态和关联关系的数据。在检索数据时应优先考虑使用HQL方式。

1.1.1 默认数据库表和数据

在讲解本章时,在没有特殊说明时,用到的数据库均为joblog,也就是在第4章建立的数据库。joblog中添加了3个表:学生表student、课程表course和选课表sc

学生表student中各字段的结构如图6-1所示,字段的中文含义在Comment列中。

6-1 学生表的数据结构

学生表student中的数据如图6-2所示,没有特殊说明时,用到的均为这6条记录。

此处仍然使用在第4章建立的HibernateProject项目,但是这里新建了一个包hibernate.ch06,这个包存放本章中的所有代码。在hibernate.ch06包中建立学生表对应的持久化类Student.java,代码如下。

6-2 学生表中的数据

package hibernate.ch06;

// 学生类

public class Student {

    private Integer id// 对象标识符

    private Integer sno;// 学号

    private String sname// 姓名

    private String ssex;// 性别

    private String sdept// 所在系别

    private Integer sage// 年龄

    private String saddress// 籍贯

    …… //省略了所有的get/set访问器

}

课程表course中的各个字段的结构如图6-3所示,字段的中文含义在Comment列中。

6-3 课程表的结构

课程表中的数据如图6-4所示,如果没有特殊说明,用到的均为这4条记录。

6-4 课程表的数据

hibernate.ch06中新建持久化类Course.java类,代码如下。

package hibernate.ch06;

// 课程类

public class Course {

    private Integer id// 对象标识符

    private Integer cno;// 课程号

    private String cname// 课程名

    private Integer Ccredit// 学分

    …… //省略了get/set访问器

}

选修表scscstudent-course的缩写)的结构如图6-5所示,字段的中文含义在Comment列中。

6-5 选修表的结构

选修表中的数据如图6-6所示,没有特殊说明时,用到的均为这5条记录。

6-6 选修表的数据

hibernate.ch06中新建持久化类SC.javaSC.java的代码如下。

package hibernate.ch06;

// 选课类

public class SC implements java.io.Serializable {

    private Integer id// id

    private Integer sno// 学号

    private Integer cno// 课程号

    private Integer grade// 成绩

    public SC() {

    }

    …… // 省略get/set访问器

}

后面的章节中将用这3个表和3个持久化类进行讲解。

1.1.2 检索类的所有对象

使用HQL语句可以检索出一个类的所有对象,如HQL语句“from Student”表示检索Student类的所有对象。下面的程序检索学生类的所有对象。

    Query query = session.createQuery("from Student"); // 创建Query对象

    List list = query.list(); // 执行查询

    

    // 以下代码做显示用,以后不再写出来

    Iterator it = list.iterator();

    while (it.hasNext()) {

        Student stu = (Student) it.next();

        System.out.println("id" + stu.getId());

        System.out.println("name" + stu.getSname());

        System.out.println("\n");

}

     session.createQuery()HQL查询语句为参数,生成一个查询对象。本例中的HQL语句为“from Student”,这是from子句,格式如下。

from 类名

其中,类名可以为类的全限定名,如:

from hibernate.ch06.Student

Hibernate使用自动引入功能(auto import),会自动寻找需要的类,所以不推荐使用类的全限定名。注意,类名区分大小写,如果写成from student,将会抛出以下异常。

java.lang.NoClassDefFoundError: hibernate/ch06/student (wrong name: hibernate/ch06/Student)

     HQL关键字不区分大小写,FROMfromFrom是一样的。

调用query.list()时,真正开始执行HQL查询语句,并把查询的结果放在List中。

本例中查询的是Student类中的所有属性,如果查询Student类中的某一个或某几个属性,如查询所有学生的姓名和所在系,需要用到属性查询。

1.1.3 检索类的某几个属性

SQL语句类似,HQL语句可以检索类的某一个或者某几个属性。以下代码查询所有学生的姓名和所在系。

    // 创建Query对象

    Query query = session.createQuery("select Student.sname,Student.sdept from Student");

    List list = query.list(); // 执行查询

    // 以下代码显示查询的信息

    Iterator it = list.iterator();

    while (it.hasNext()) {

        Object[] stu = (Object[]) it.next();

        System.out.println("id" + stu[0]);

        System.out.println("name" + stu[1]);

        System.out.println("\n");

}

     属性查询使用select关键字,属性查询的格式如下。

select 属性1,属性2,… from 类名

     属性前可以加上类名加以限定,如:

select 属性1,属性2,… from 类名

但一般没有必要。

属性查询区分大小写,上面的代码中如果写成:

select SNAME,Sdept from Student

将抛出异常,提示找不到属性SNAME和属性Sdept

     查询结果将只显示查询的属性列。

     属性查询的结果,对于用it.next()获得的每条记录,可以存储在Object[]数组中,以便进行存取。

1.1.4 指定别名

在查询时,可以用关键字as指定查询的别名,指定别名可以简化查询,有时必需指定别名才能进行查询。以下代码查询学号中含有4的学生的姓名和所在系。

select s.sname,s.sdept from Student as s where s.sno like '%4%'from Student s

s就是类Student的别名。注意as可以省略,即下面的查询语句和上面的语句是等效的。

select s.sname,s.sdept from Student s where s.sno like '%4%'from Student s

1.1.5 where条件子句

where条件子句跟SQL中的where条件子句类似,它检索符合条件的对象。例如,查询所有所在系别为计算机系的学生:

select s.sname,s.sdept from Student s where s.dept=’计算机

     where子句指定查询的条件,其语法和SQL类似。

     where子句中可以指定比较运算符:>>=<<=<>,其含义分别为大于、大于等于、小于、小于等于、不等于。

查询年龄在2223岁的学生:

from Student s where s.sage>=22 and s.sage<=23

     where子句中指定查询的属性是否为nullis nullis not null,其含义分别表示为空和不为空。

查询所在籍贯为空的学生:

from Student s where s.saddress is null

1.1.6 使用distinct过滤掉重复值

使用distinct关键字将去掉结果中的重复值,只检索符合条件的对象。如下面的例子检索学生实例中的不重复的年龄。

        Session session=Hsf.currentSession();//创建Session

        String hql="select distinct s.sage from Student s";       //HQL查询语句

        Query query=session.createQuery(hql);//创建查询

        List list=query.list();    //执行查询

检索的结果如下,可见结果中去掉了一个重复的22岁。

20

21

22

23

24

1.1.7 删除对象

HQL语句可以直接对复合条件的对象进行删除,可以指定删除的对象,并在提交后永久持久化到数据库。HQL使用delete进行删除,如删除年龄大于25岁的学生可以使用如下代码。

        Session session=Hsf.currentSession();        //创建Session

        Transaction tx=null;       //声明事务

        

        try{

   tx=session.beginTransaction();  //开始事务

           

  //创建查询

   String hql="delete Student s where s.sage>25";

   Query query=session.createQuery(hql);

   query.executeUpdate();           //执行

 tx.commit();           //成功,则提交

   tx=null;

        }catch(Exception e){

   e.printStackTrace();

   if(tx!=null){

  tx.rollback();    //失败则回滚

       

    }

        }finally{

   session.close();

        }

注意以下两点。

     在删除对象时,执行query.executeUpdate()进行数据删除,但只有执行了tx.commit()进行事务提交时,才真正从数据库中删除数据。

     如果设置了级联删除,则与之相关联的对象实例也被删除。

1.1.8 更新对象值

更新对象的HQL语句与SQL语法很相似,使用update更新对象的值。如下面例子更新对象的sage属性。

        ransaction tx=null;         //声明事务

        try{

   tx=session.beginTransaction();  //开始事务

           

   String hql="update Student s set s.sage='22' where s.id=11";   //更新语句

   Query query=session.createQuery(hql);

   query.executeUpdate();           //执行

   tx.commit();           //成功,则提交

   tx=null;

        }catch(Exception e){

   e.printStackTrace();

   if(tx!=null){

           tx.rollback(); //失败则回滚

   }

        }finally{

   session.close();

        }

1.1.9 查询计算属性值

HQL可以查询经过计算的值,在一些需要计算的地方可以进行计算,例如查询全体学生的姓名和出生年份。

select s.sname,2006-s.sage from Student as s

     select子句十分灵活,几乎和SQL语句有着同样的能力,对象的属性值可以参与运算。

     这行代码假设当前的年份是2006年。

下面是另外几个查询计算属性值的例子。

select s.sname,2006-s.sage from Student as s

1.1.10 使用函数

当需要调用函数时,HQL提供了一些类似SQL的函数。这些函数可以简化操作。例如查询学生的姓名、出生日期和性别,其中性别用小写表示。

select s.sname,2006-s.sage,lower(s.ssex) from Student as sselect s.sname,2006-s. sage from Student as s

1.1.11 between...and...not between... and...确定查询范围

between...and...用来查询属性值在指定范围内的实体对象,not between...and...用来查询属性值不在指定范围内的实体对象。如查询学生年龄在2223之间的学生:

select s.sno,s.sname,s.sage from Student s where s.sage between 22 and 23

查询将返回如下结果。

---------------------------------------------------------------------

1    20040001 李晓梅    22    计算机系   

---------------------------------------------------------------------

2    20040002 王蒙       23    外语系   

---------------------------------------------------------------------

4    20050004 李文       22    计算机系   

between后跟的是查询范围的下限,and后跟的是查询范围的上限,所以下面的查询语句总没有对象返回。

from Student s where s.sage between 23 and 22

1.1.12 innot in确定查询集合

关键字in用来查询指定属性值属于指定集合的对象,关键字not in用来查询指定属性值不属于指定集合的对象。如查询不是计算机系,也不是数学系的学生。

select s.sno,s.sname,s.sdept from Student s where s.sdept not in ('计算机系','数学系')

查询将返回如下结果。

---------------------------------------------------------------------

20040002         王蒙         外语系   

---------------------------------------------------------------------

20050003         姜浩         化学系   

---------------------------------------------------------------------

20050005         薛鹏         生物系   

1.1.13 like进行模糊查询

like进行模糊查询时有两个可用的通配符:“%”“_”“%”代表长度大于等于0的字符,“_”代表长度为1的单个字符。

查询姓李的学生:

select s.sno,s.sname,s.sdept from Student s where s.sname like '%%'

查询结果如下。

---------------------------------------------------------------------

20040001         李晓梅    计算机系   

---------------------------------------------------------------------

20050004         李文       计算机系   

---------------------------------------------------------------------

20050006         李思       数学系   

查询姓名为两个字符的学生:

select s.sno,s.sname,s.sdept from Student s where s.sname like '__'

查询结果如下。

---------------------------------------------------------------------

20040002    王蒙    外语系   

---------------------------------------------------------------------

20050003    姜浩    化学系   

---------------------------------------------------------------------

20050004    李文    计算机系   

---------------------------------------------------------------------

20050005    薛鹏    生物系   

---------------------------------------------------------------------

20050006    李思    数学系   

1.1.14 and逻辑与

当要检索指定的多个条件,且条件的逻辑关系为与时,使用“and”关键字。如检索计算机系的女生,这个检索要求包含两个条件:计算机系女生

select s.sno,s.sname,s.sdept from Student s where s.sdept='计算机系' and s.ssex='F'

检索的结果如下。

---------------------------------------------------------------------

20040001         李晓梅    计算机系   

---------------------------------------------------------------------

20050004         李文      计算机系   

1.1.15 or逻辑或

当检索的多个条件,且条件的逻辑关系为或时,使用“or”关键字。如检索姓王,或者年龄大于22岁的学生:

select s.sno,s.sname,s.sdept from Student s where s.sname like '%' or s.sage>22

检索结果如下。

---------------------------------------------------------------------

20040002         王蒙         外语系   

---------------------------------------------------------------------

20050005         薛鹏         生物系

1.1.16 order by对结果进行排序

“order by”关键字对结果进行排序,默认为升序。“order by asc”为升序,“order by desc”为降序。例如将学生表中的学生按照年龄升序排序:

from Student s order by s.sage

检索结果如下。

---------------------------------------------------------------------

6    20050006         李思         20         数学系   

---------------------------------------------------------------------

3    20050003         姜浩         21         化学系   

---------------------------------------------------------------------

1    20040001         李晓梅      22        计算机系   

---------------------------------------------------------------------

4    20050004         李文         22         计算机系   

---------------------------------------------------------------------

2    20040002         王蒙         23         外语系   

---------------------------------------------------------------------

5    20050005         薛鹏         24         生物系   

将学生表中的学生按照年龄降序排列,按照所在系升序排列。

from Student s order by s.sage,s.sdept desc

1.1.17 group by对记录进行分组

对查询进行分组可以对查询进行细化。分组经常和聚集函数一起使用,这样聚集函数将作用于每个分组。

     group by的用法为:

select 属性1,属性2,属性,属性n from 类名 group by 属性m

     其中属性1,属性2,属性n必须满足下列条件。

要么作为聚集函数的参数,要么为属性m。例如,检索各个系的学生的平均年龄:

select avg(s.sage),s.sdept from Student s group by s.sdept

其中字段s.sage作为平均值函数的参数,s.sdeptgroup by后的一个属性。检索的结果如下。

---------------------------------------------------------------------

化学系         21.0   

---------------------------------------------------------------------

计算机系       22.0   

---------------------------------------------------------------------

生物系         24.0   

---------------------------------------------------------------------

数学系         20.0   

---------------------------------------------------------------------

外语系         23.0   

检索各个课程号与对应的选课人数。

select cno,count(sno) from SC s group by s.cno

1.1.18 having关键字

having关键字和group by关键字搭配使用,它对分组后的记录进行筛选,输出符合having指定条件的组。例如查询人数超过1000人的系。

select s.sdept from Student s group by s.sdept having count(*)>1000

查询男生人数多于500人的系。

select s.sdept from Student s where s.ssex=’M’ group by s.sdept having count(*)>500

     以上面查询男生人数多于500人的系为例:

select s.sdept from Student s where s.ssex=’M’ group by s.sdept having count(*)>500

查询过程中同时使用group byhaving关键字时,查询步骤如下。

1)检索符合s.ssex=‘M’的所有男生。

2)根据s.sdept分组成不同的系。

3)对于每一个分组,计算分组中的记录条数大于500的系。

4)将符合上述条件的s.sdept选出来。

     wherehaving的区别在于作用对象不同。where作用于基本表,而having作用于分组后的组。

1.1.19 聚集函数

聚集函数包括count()avg()sum()max()min(),其含义如表6-1所示。

6-1         聚集函数及其含义

聚 集 函 数

    

count()

计算符合条件的记录条数

avg()

计算符合条件的平均值

sum()

计算符合条件的和

max()

计算符合条件的最大值

min()

计算符合条件的最小值

     各个函数的用法举例如下。

检索学生实例的对象个数:

select count(*) from Student

检索计算机系的人数:

select count(*) from Student s where s.sdept='计算机系'

检索学生实例的平均年龄:

select avg(s.sage) from Student s

检索课程表course的所有课程的学分的总和:

select sum(c.ccredit) from Course c

检索课程号为“1”的课程的最高成绩:

select max(s.grade) from SC s where s.cno=1

检索课程号为“1”的课程的最低成绩:

select min(s.grade) from SC s where s.cno=1

     聚集函数经常和group by分组关键字搭配使用。

检索各门课程的平均成绩:

select s.cno,avg(s.grade) from SC s group by s.cno

检索各科不及格人数:

select s.cno,count(*) from SC s where s.grade<60 group by s.cno

1.2 HQL进阶

下面讲述HQL一些比较高级的应用,包括如何使用HQL查询继承关系数据、绑定参数和在配置文件中使用查询语句。

1.2.1 查询类及其所有继承的类的实例

默认情况下,当查询一个类时,Hibernate会自动搜索这个类的所有继承类。假如有如下3个类,类的关系如图6-7所示。

6-7 Animal类及其子类BirdMammal

当调用如下HQL语句时,会查询出所有的Animal实例、Bird实例和Mammal实例。

from Animal

所有的类均继承自java.lang.Object,所以下面的HQL语句查询所有的类的对象实体,即查询所有映射表的记录。

from java.lang.Object

1.2.2 限制每次查询的返回对象数

Query接口提供了两个函数,用于限制每次查询返回的对象数。

     SetFirstResult(int firstResult) 用于设置从哪一个对象开始检索。参数firstResult设置开始检索的起始记录。

     setMaxResults(int maxResults) 用于设置每次检索返回的最大对象数。参数maxResults用于设置每次检索返回的对象数目。

这两个函数结合起来用,经常用于分页显示对象。例如数据库中有10000条记录,如果一次性显示实在太多,就可以进行分页显示。

下面的程序当每次循环时,从Student实例中检索出pageSize个对象,并输出到控制台,是一个典型的分页显示程序。

   /**

 * 分页输出对象

 * 

 * @param pageSize

 *            每页显示的记录条数

 */

public void pagenate(int pageSize) {

    Session session = Hsf.currentSession(); // 创建Session

    String hql = "from Student";// 检索Student

抱歉!评论已关闭.