hql基础

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

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

6.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访问器

}

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



图6-5  选修表的结构

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



图6-6  选修表的数据

在hibernate.ch06中新建持久化类SC.java,SC.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个持久化类进行讲解。

6.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关键字不区分大小写,FROM、from和From是一样的。

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

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

6.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[]数组中,以便进行存取。

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

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

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

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

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

查询年龄在22到23岁的学生:

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

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

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

from Student s where s.saddress is null

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

        Session session=HibernateSessionFactory.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

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

        Session session=HibernateSessionFactory.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()进行事务提交时,才真正从数据库中删除数据。

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

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

        }

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

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

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

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

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

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

查询将返回如下结果。

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

20040002        王蒙        外语系   

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

20050003        姜浩        化学系   

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

20050005        薛鹏        生物系   

6.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    李思    数学系   

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

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

检索的结果如下。

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

20040001        李晓梅    计算机系   

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

20050004        李文      计算机系   

6.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        薛鹏        生物系

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

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

     group by的用法为:

select 属性1,属性2,属性3 ,…,属性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.sdept是group by后的一个属性。检索的结果如下。

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

化学系        21.0   

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

计算机系      22.0   

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

生物系        24.0   

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

数学系        20.0   

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

外语系        23.0   

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

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

6.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 by和having关键字时,查询步骤如下。

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

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

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

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

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

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

你可能感兴趣的:(数据结构,sql,框架,Hibernate,生物)