HQL全称是Hibernate Query Language,它提供了是十分强大的功能,它是针对持久化对象,直接取得对象,而不进行update,delete和insert等操作。而且HQL是面向对象的,具备继承,多态和关联等特性。
HQL的语法类似于SQL,其常用的方法如下:
[select|update|delete 子句] [from 类名列表] [where 子句] [group by 子句] [order by 子句]
[select|update|delete 子句]用于查询,更新和删除。
[from 类名列表]指定查询的持久化类所在的的数据表名。[where 子句]给出查询的条件。
[group by 子句]用于对数据进行分组。
[order by 子句]对查询结果进行排序。
注意:除了Java类与属性的名称外,HQL查询语句对大小写并不敏感。 所以 SeLeCT 与 sELEct 以及 SELECT 是相同的,但是 org.hibernate.eg.FOO 并不等价于 org.hibernate.eg.Foo 并且 foo.barSet 也不等价于 foo.BARSET。
二、HQL语法详解
-----[select|update|delete]--------
select关键词后跟的是需要返回的对象或者对象属性,且属性必须属于from子句中给出的类列表。使用select可以直接存入一个List对象或直接封装为一个对象。
使用示例:
1、查询具体属性
select stu.cores.english from Student as stu;
上述语句查询出学生的英语成绩
2、查询并放入List对象
select new List(stu.id,stu.name) from Student as stu;
查询了学生的学号和名字,放入一个List中
3、查询并生成对象
select new Student(stu.id,stu.name) from Student as stu;
查询了学生的学号和名字,并生成一个Student对象。使用前提:Student类中存在相应的构造方法。
4、查询所有属性
from Student
多数情况下,我们可以为查询的实体对象指定一个别名,方便在其他地方引用。
from Student as stu
update和delete是Hibernate3新加入的特性。这样我们更新数据库就有两种方式。
1、先修改持久化对象的值,之后提交事务更新数据。
2、使用HQL语句实现。不过不推荐这种方式。
---------from子句-----------
from子句是最简单的HQL,例如from Student,也可以写成 select s from Student s。它简单的返回Student类的所有实例。
---------where子句----------
HQL也支持子查询,它通过where子句实现这一机制。where子句可以让用户缩小要返回的实例的列表范围。例如下面语句会返回所有名字为"kang"的Student实例:
Query query = session.createQuery("from Student as stu where stu.name='kang'");
1、where子句允许出现的表达式
数学操作:+,-,*,/
真假比较操作:=, >=, <=, <>, !=, like
逻辑操作:and ,or, not
字符串连接:||
SQL标题函数 :如upper()和lower()
2、如果查询返回多条记录,可以用以下关键字来量化
all:表示所有的记录。
any:表示所有记录中的任意一条。
some:与any相同。
in:与any等价。
exists:表示子查询至少要返回一条记录。
查询示例:
返回所有学生年龄都大于18的班级对象
from Group g where 18<all (select s.age from g.students s)
返回在所有学生中有一个学生的年龄等于22的班级:
from Group g where 22 = any (select s.age from g.students s)
或者
from Group g where 22= some(select s.age from g.students s)
或者
from Group g where 22 in (select s.age from g.students s)
-----------Group by子句--------------
在HQL语句中同样支持使用group by子句分组查询,还支持group by子句结合聚集函数的分组统计查询,大部分标准的SQL聚集函数都可以在HQL语句中使用,比如:
count(),sum(),max(),min(),avg()等。(前提是数据库支持having语句,例如mysql不支持)
count():统计记录条数。
min():求最小值。
max():求最大值。
sum():求和。
avg():求平均值。
例如,要取得Student实例的数量,可以编写如下HQL语句:
select count(*) from Student
取得Student平均年龄的HQL语句:
select avg(s.age) from Student as s
可以使用distinct去除重复的数据:
select distinct s.age from Student as s
如下面的程序代码:
String hql=”select count(user),user.age from User user group by user.age having count(user)>10 ”;//mysql不行
List list=session.createQuery(hql).list();
--------------order by子句------------
查询返回列表可以按照任何返回的类或者组件的属性排序,asc为正序排列(从小到大),desc为降序排列(从大到小)
按照学生的学号正序排列
from Studen as stu order by stu.id asc
---------------联合查询--------------
与SQL一样,HQL也支持连接查询,如内连接,外连接和交叉连接:
inner join:内连接
left outer join:左外连接
rigth outer join:右外连接
full join:全连接,但不常用
下面重点介绍下内连接查询,左外连接和或右外连接和内连接大同小异,而全连接几乎没有使用得到的地方。
inner join可以简写为join,例如在查询得到的Group对象时,内连接取得对应的Student对象,实现的程序代码如下:
Student stu = null; Group group = null; Query query = session.createQuery("from Group g join g.students"); List list = query.list(); Object obj[] = null; for(int i = 0 ; i < list.size(); i++) { obj = (Object[])list.get(i); group = (Group)obj[0];//group是数组是第一个对象 stu = (Student)obj[1];//stu是数组的第二个对象 System.out.println(stu.getName()+"属于"+group.getName()); }
对于支持子查询的数据库,Hibernate支持在查询中使用子查询。一个子查询必须被圆括号包围起来(经常是SQL聚集函数的圆括号)。 甚至相互关联的子查询(引用到外部查询中的别名的子查询)也是允许的。
from Cat as fatcat where fatcat.weight > (select avg(cat.weight) from DomesticCat cat)
---------------参数绑定--------------
Hibernate中对动态查询参数绑定提供了丰富的支持,那么什么是查询参数动态绑定呢?其实如果我们熟悉传统JDBC编程的话,我们就不难理解查询参数动态绑定,
如下代码传统JDBC的参数绑定:
PrepareStatement pre=connection.prepare(“select * from User where user.name=?”);
pre.setString(1,”xiaokang”);
ResultSet rs=pre.executeQuery();
在Hibernate中也提供了类似这种的查询参数绑定功能,而且在Hibernate中对这个功能还提供了比传统JDBC操作丰富的多的特性,在Hibernate中共存在4种参数绑
定的方式,下面我们将分别介绍:
1、按参数名称绑定:
在HQL语句中定义命名参数要用”:参数名”的形式,形式如下:
Query query=session.createQuery(“from User user where user.name=:customername and user.customerage=:age ”);
query.setString(“customername”,name);
query.setInteger(“customerage”,age);
上面代码中用:customername和:customerage分别定义了命名参数customername和customerage,然后用Query接口的setXXX()方法设定名参数值,setXXX()方法包
含两个参数,分别是命名参数名称和命名参数实际值。
2、按参数位置邦定:
在HQL查询语句中用”?”来定义参数位置,形式如下:
Query query=session.createQuery(“from User user where user.name=? and user.age =? ”);
query.setString(0,name);
query.setInteger(1,age);
同样使用setXXX()方法设定绑定参数,只不过这时setXXX()方法的第一个参数代表邦定参数在HQL语句中出现的位置编号(由0开始编号),第二个参数仍然代表参数实际值。
注:在实际开发中,提倡使用按名称邦定命名参数,因为这不但可以提供非常好的程序可读性,而且也提高了程序的易维护性,因为当查询参数的位置发生改变时,按名称邦定名参数的方式中是不需要调整程序代码的。
3、setParameter()方法:
在Hibernate的HQL查询中可以通过setParameter()方法邦定任意类型的参数,如下代码:
String hql=”from User user where user.name=:customername ”;
Query query=session.createQuery(hql);
query.setParameter(“customername”,name,Hibernate.STRING);
如上面代码所示,setParameter()方法包含三个参数,分别是命名参数名称,命名参数实际值,以及命名参数映射类型。对于某些参数类型setParameter()方法可以更具参数值的Java类型,猜测出对应的映射类型,因此这时不需要显示写出映射类型,像上面的例子,可以直接这样写:
query.setParameter(“customername”,name);但是对于一些类型就必须写明映射类型,比如java.util.Date类型,因为它会对应Hibernate的多种映射类型,比如
Hibernate.DATA或者Hibernate.TIMESTAMP。
4、setProperties()方法:
在Hibernate中可以使用setProperties()方法,将命名参数与一个对象的属性值绑定在一起,如下程序代码:
Customer customer=new Customer(); customer.setName(“pansl”); customer.setAge(80); Query query=session.createQuery(“from Customer c where c.name=:name and c.age=:age ”); query.setProperties(customer);
这里还有一个特殊的setEntity()方法,它会把命名参数与一个持久化对象相关联,如下面代码所示:
Customer customer=(Customer)session.load(Customer.class,”1”); Query query=session.createQuery(“from Order order where order.customer=:customer ”); query. setProperties(“customer”,customer); List list=query.list();
上面的代码会生成类似如下的SQL语句:
Select * from order where customer_ID=’1’;
三、如何使用HQL语句
HQL查询依赖于Query类,每个Query实例对应一个查询对象,使用HQL查询按如下步骤进行:
1.获取Hibernate Session对象
2.编写HQL语句
3.以HQL语句作为参数,调用Session的createQuery方法创建查询对象
4.如果HQL语句包含参数,则调用Query的setXxx方法为参数赋值
5.调用Query独享的list()或uniqueResult()方法返回查询结果列表
例如:
Session s = null; try{ s = HibernateUtil.getSession();//获取session,前提HibernateUtil中有一个静态方法getSession String hql = "from Test as test where test.name=?"; Query query = s.createQuery(hql);//创建Query对象 query.setString(0,name);//设置参数 List list = query.list();//查询结果 for(Test test:list){//遍历 System.out.println(test.getName()); } }finally{ //finally表示数据库一定要被关闭 if(s!=null) s.close(); } } }