题记:写这篇博客要主是加深自己对查询参数的认识和总结实现算法时的一些验经和训教,如果有错误请指出,万分感谢。
HQL查询:
Criteria查询对查询条件行进了面向对象装封,符合程编员人的思维式方,不过HQL(Hibernate Query Lanaguage)查询供给了更加富丰的和活灵的查询性特,因此
Hibernate将HQL查询式方立为官方推荐的标准查询式方,HQL查询在涵盖Criteria查询的有所功能的前提下,供给了似类标准SQL句语的查询式方,同时也供给了更
加面向对象的装封。完全的HQL句语势形如下:
Select/update/delete…… from …… where …… group by …… having …… order by …… asc/desc
其中的update/delete为Hibernate3中所新加添的功能,可见HQL查询非常似类于标准SQL查询。
1、 体实查询:
有关体实查询技巧,其实我们在先前已经有多次及涉,比如上面的例子:
String hql=”from User user ”;
List list=session.CreateQuery(hql).list();
面上的码代执行结果是,查询出User体实对象所对应的有所数据,而且将数据装封成User体实对象,并且放入List中回返。这里须要注意的是,Hibernate的体实查
询存在着对继承系关的定判,比如我们后面探讨映射体实继承系关中的Employee体实对象,它有两个子类分离是HourlyEmployee,SalariedEmployee,如果有这样的
HQL句语:“from Employee”,当执行检索时Hibernate会检索出有所Employee类型体实对象所对应的数据(括包它的子类HourlyEmployee,SalariedEmployee对应
的数据)。
因为HQL句语与标准SQL句语相似,所以我们也可以在HQL句语中应用where字句,并且可以在where字句中应用各种表达式,比拟作操符以及应用“and”,”or”接连
不同的查询条件的合组。看上面的一些单简的例子:
from User user where user.age=20;
from User user where user.age between 20 and 30;
from User user where user.age in(20,30);
from User user where user.name is null;
from User user where user.name like ‘%zx%’;
from User user where (user.age%2)=1;
from User user where user.age=20 and user.name like ‘%zx%’;
2、 体实的更新和删除:
在继承讲授HQL其他更为大强的查询功能前,我们先来讲授以下利用HQL行进体实更新和删除的技巧。这项技巧功能是Hibernate3的新入加的功能,在Hibernate2
中是不具备的。比如在Hibernate2中,如果我们想将数据库中有所18岁的用户的春秋全体为改20岁,那么我们要首先将春秋在18岁的用户检索出来,然后将他们的
春秋修为改20岁,最后调用Session.update()句语行进更新。在Hibernate3中对这个问题供给了更加活灵和更具效率的解决办法,如上面的码代:
Transaction trans=session.beginTransaction();
String hql=”update User user set user.age=20 where user.age=18”;
Query queryupdate=session.createQuery(hql);
int ret=queryupdate.executeUpdate();
trans.commit();
通过这类式方我们可以在Hibernate3中,一次性成完量批数据的更新,对性能的高提是相称的可观。一样也可以通过似类的式方来成完delete作操,如上面的码代
:
Transaction trans=session.beginTransaction();
String hql=”delete from User user where user.age=18”;
Query queryupdate=session.createQuery(hql);
int ret=queryupdate.executeUpdate();
trans.commit();
如果你是个逐章节读阅的化,那么你一定会记起我在第二分部中有关量批数据作操的相干述论中,探讨过这类作操式方,这类作操式方在Hibernate3中称为bulk
delete/update,这类式方够能在很大程度上高提作操的活灵性和运行效率,但是采取这类式方极有可能引发缓存同步上的问题(请参考相干述论)。
3、 属性查询:
很多时候我们在检索数据时,并不须要得获体实对象所对应的全体数据,而只须要检索体实对象的分部属性所对应的数据。这时候就够能利用HQL属性查询技巧
,如上面程序示例:
List list=session.createQuery(“select user.name from User user ”).list();
for(int i=0;i<list.size();i++){
System.out.println(list.get(i));
}
我们只检索了User体实的name属性对应的数据,此时回返的括包结果集的list中每一个条目都是String类型的name属性对应的数据。我们也可以一次检索多个属性,
如上面程序:
List list=session.createQuery(“select user.name,user.age from User user ”).list();
for(int i=0;i<list.size();i++){
Object[] obj=(Object[])list.get(i);
System.out.println(obj[0]);
System.out.println(obj[1]);
}
此时回返的结果集list中,所括包的每一个条目都是一个Object[]类型,其中括包对应的属性数据值。作为今当我们这一代深受面向对象想思影响的开辟员人,可能
会认为面上回返Object[]不敷符合面向对象风格,这时我们可以利用HQL供给的态动造构实例的功能对这些平面数据行进装封,如上面的程序码代:
List list=session.createQuery(“select new User(user.name,user.age) from User user ”).list();
for(int i=0;i<list.size();i++){
User user=(User)list.get(i);
System.out.println(user.getName());
System.out.println(user.getAge());
}
这里我们通过态动造构实例对象,对回返结果行进了装封,使我们的程序更加符合面向对象风格,但是这里有一个问题必须注意,那就是这时所回返的User对象,
仅仅只是一个通普的Java对象而以,除了查询结果值以外,其它的属性值都为null(括包主键值id),也就是说不能通过Session对象对此对象执行持久化的更新操
作。如上面的码代:
List list=session.createQuery(“select new User(user.name,user.age) from User user ”).list();
for(int i=0;i<list.size();i++){
User user=(User)list.get(i);
user.setName(“gam”);
session.saveOrUpdate(user);//这里将会际实执行一个save作操,而不会执行update作操,因为这个User对象的id属性为null,Hibernate会把它作为一个由自对
象(请参考持久化对象状态分部的述论),因此会对它执行save作操。
}
4、 组分与排序
A、Order by子句:
与SQL句语相似,HQL查询也可以通过order by子句对查询结果集行进排序,并且可以通过asc或者desc关键字指定排序式方,如上面的码代:
from User user order by user.name asc,user.age desc;
面上HQL查询句语,会以name属性行进升序排序,以age属性行进降序排序,而且与SQL句语一样,认默的排序式方为asc,即升序排序。
B、Group by子句与计统查询:
在HQL句语中一样支撑应用group by子句组分查询,还支撑group by子句结合集聚函数的组分计统查询,大分部标准的SQL集聚函数都可以在HQL句语中应用,比如:
count(),sum(),max(),min(),avg()等。如上面的程序码代:
String hql=”select count(user),user.age from User user group by user.age having count(user)>10 ”;
List list=session.createQuery(hql).list();
C、化优计统查询:
假设我们在现有两张数据库表,分离是customer表和order表,它们的构结如下:
customer
ID varchar2(14)
age number(10)
name varchar2(20)
order
ID varchar2(14)
order_number number(10)
每日一道理
天又快黑了,这座忙碌的城市又将入睡,让这劳累的“身躯”暂别白日的辛勤,让它入睡,陪伴着城市中的人们进入梦乡。当空的弯月正深情地注视着这座城市与城市中的人们,看着家家户户的灯渐渐熄灭,它在床头悄悄奏响“明月曲”……
customer_ID varchar2(14)
在现有两条HQL查询句语,分离如下:
from Customer c inner join c.orders o group by c.age;(1)
select c.ID,c.name,c.age,o.ID,o.order_number,o.customer_ID
from Customer c inner join c.orders c group by c.age;(2)
这两条句语应用了HQL句语的内接连查询(我们将在HQL句语的接连查询分部专门探讨),在现我们可以看出这两条查询句语最后所回返的结果是一样的,但是它们
实际上是有显明区分的,句语(1)检索的结果会回返Customer与Order持久化对象,而且它们会被置于Hibernate的Session缓存中之,并且Session会责负它们在缓存
中的唯一性以及与台后数据库数据的同步,只有务事提交后它们才会从缓存中被清除;而句语(2)回返的是系关数据而并非是持久化对象,因此它们不会占用
Hibernate的Session缓存,只要在检索后之应用程序不在拜访它们,它们所占用的存内就有可能被JVM的垃圾收回器收回,而且Hibernate不会同步对它们的修改。
在我们的系统开辟中,尤其是Mis系统,不可防止的要行进计统查询的开辟,这类功能有两个特色:第一数据量大;第二一般情况下都是只读作操而不会及涉到对统
计数据行进修改,那么如果采取第一种查询式方,必然会致使量大持久化对象位于Hibernate的Session缓存中,而且Hibernate的Session缓存还要责负它们与数据
库数据的同步。而如果采取第二种查询式方,显明就会高提查询性能,因为不须要Hibernate的Session缓存的管理开销,而且只要应用程序不在应用这些数据,它
们所占用的存内空间就会被收回释放。
因此在开辟计统查询系统时,尽量应用通过select句语写出须要查询的属性的式方来回返系关数据,而防止应用第一种查询式方回返持久化对象(这类式方是在有
修改求需时应用比拟合适),这样可以高提运行效率并且增加存内消费。㊣真正的妙手并非通精一切,而是通精在合适的合场应用合适的段手。
5、 参数定绑:
Hibernate中对态动查询参数定绑供给了富丰的支撑,那么什么是查询参数态动定绑呢?其实如果我们熟习传统JDBC程编的话,我们就不难理解查询参数态动定绑,
如下码代传统JDBC的参数定绑:
PrepareStatement pre=connection.prepare(“select * from User where user.name=?”);
pre.setString(1,”zhaoxin”);
ResultSet rs=pre.executeQuery();
在Hibernate中也供给了似类这类的查询参数定绑功能,而且在Hibernate中对这个功能还供给了比传统JDBC作操富丰的多的性特,在Hibernate中共存在4种参数绑
定的式方,上面我们将分离分析:
A、 按参数称名定绑:
在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()方法包
含两个参数,分离是名定参数称名和名定参数际实值。
B、 按参数位置邦定:
在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开始编号),第二个参数仍然代表参
数际实值。
注:在际实开辟中,提倡应用按称名邦定名定参数,因为这不但可以供给非常好的程序可读性,而且也高提了程序的易护维性,因为当查询参数的位置发生变改时
,按称名邦名定参数的式方中是不须要调整程序码代的。
C、 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。
D、 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);
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’;
E、 应用定绑参数的优势:
我们为什么要应用定绑名定参数?任何一个事物的存在都是有其代价的,详细到定绑参数对于HQL查询说来,重要有以下两个重要优势:
①、 可以利用数据库施实性能化优,因为对Hibernate说来在底层应用的是PrepareStatement来成完查询,因此对于法语雷同参数不同的SQL句语,可
以充分利用预编译SQL句语缓存,从而晋升查询效率。
②、 可以防止SQL Injection安全漏洞的发生:
SQL Injection是一种专门针对SQL句语拼装的攻击式方,比如对于我们罕见的用户录登,在录登界面上,用户入输用户名和口令,这时录登验证程序可能会生成如
下的HQL句语:
“from User user where user.name=’”+name+”’ and user.password=’”+password+”’ ”
这个HQL句语从逻辑上说来是没有任何问题的,这个录登验证功能在一般情况下也是会确正成完的,但是如果在录登时在用户名中入输”zhaoxin or ‘x’=’x”,
这时如果应用单简的HQL句语的字符串拼装,就会生成如下的HQL句语:
“from User user where user.name=’zhaoxin’ or ‘x’=’x’ and user.password=’admin’ ”;
显明这条HQL句语的where字句将会永远为真,而应用户口令的作用得到义意,这就是SQL Injection攻击的基本原理。
而应用定绑参数式方,就够能妥善处理这问题,当应用定绑参数时,会到得上面的HQL句语:
from User user where user.name=’’zhaoxin’’ or ‘’x=’’x’’ ‘ and user.password=’admin’;由此可见应用定绑参数会将用户名中入输的单引号解
析成字符串(如果想在字符串中括包单引号,应应用重复单引号情势),所以参数定绑够能效有防止SQL Injection安全漏洞。
分页查询:
setFirstResult(int firstResult):设定从个一哪对象开始检索,参数firstResukt示表这个对象在查询结果中的索引位置,索引位置的起始值为0,认默情况下,Query从查询结果中的第一个对象开始检索。
setMaxResult(int maxResults):设定一次最多检索出的对象的目数,在认默情况下,Query和Criteria接口检索出查询结果中有所对象。
EG://HQL查询
Query query=session.createQuery(“from User user order by user.id”);
query.setFirstResult(3);
query.setMaxResults(4);
query.list();
详细小实例分页查询:
public static void query(String name){
Session s=null;
try{
s=HibernateUtil.getSession();
hibernate的查询语言.from面后+类名(区分大小写).也可以用as给类起一个名别,as可以省略
//按照姓名查找
String queryString="from 类名 as 类的名别 where 类的名别.name=:n";
Query query=s.createQuery(queryString);
query.setString("n",name);
//分页表现的作操
query.setFirstResult(2);//表现第几页,当前页
query.setMaxResults(2);//每页做多表现的录记数
//回返多行结果集
List<User> list=query.list();
for(User u:list){
System.out.println(u.getId()+":"+u.getName());
}
/*User user=(User) query.uniqueResult();
System.out.println(user.getId()+":"+user.getName());*/
/*query.uniqueResult();//回返一行结果集*/
}finally{
if(s!=null){
s.close();
}
}
}
文章结束给大家分享下程序员的一些笑话语录: 一个程序员对自己的未来很迷茫,于是去问上帝。
"万能的上帝呀,请你告诉我,我的未来会怎样?"
上帝说"我的孩子,你去问Lippman,他现在领导的程序员的队伍可能是地球上最大的"
于是他去问Lippman。
Lippman说"程序员的未来就是驾驭程序员"
这个程序员对这个未来不满意,于是他又去问上帝。
"万能的上帝呀,请你告诉我,我的未来会怎样?"
上帝说"我的孩子,你去问Gates,他现在所拥有的财产可能是地球上最多的"
于是他去问Gates。
Gates说"程序员的未来就是榨取程序员"
这个程序员对这个未来不满意,于是他又去问上帝。
"万能的上帝呀,请你告诉我,我的未来会怎样?"
上帝说"我的孩子,你去问侯捷,他写的计算机书的读者可能是地球上最多的"
于是他去问侯捷。
侯捷说"程序员的未来就是诱惑程序员"
这个程序员对这个未来不满意,于是他又去问上帝。
"万能的上帝呀,请你告诉我,我的未来会怎样?"
上帝摇摇头"唉,我的孩子,你还是别当程序员了")