hibernate 多张表关联中多张表连接,要求左连接,HQL语句怎么整

10225人阅读
对象之间总是有各种各样的关系,关联关系是类之间最常见的关系。多表查询是HQL中的强大功能之一,包括内连接、左连接和右连接等。多表查询的设置及运行都比较麻烦,在运行本节中的示例时,务必保证每一步都没有错误。&
6.4.1& 表之间的关联关系&
在数据库joblog中用到了3个表:student(学生表)、course(课程表)和sc(选课表)。这些表的详细信息见6.1.1节“示例中用到的默认数据库表和数据”。在现实模型中,一个学生可以选择多门课程,一个课程可以被多个学生选择,student和course是多对多的关联关系。为了便于演示HQL的多表查询,本节中假设student和course之间是单向关联关系。&
在多对多的关联关系中,一般来说有个中间表,这个表描述了多对多关系,这就是选课表sc,sc每一行数据代表一个学生的选课和成绩。&
各个表的主键、外键设置如下。&
student表的主键是id字段。&
course表的主键是id字段。&
sc表的主键是id字段。&
sc表中的Sno字段是student表id字段的外键。&
sc表中的Cno字段是course表id字段的外键。&
图6-8是3个表之间关系的直观表示。&
图6-8& 3个表之间的关系&
在MySQL Query Browser中设置好上述关系。如果此处设置不正确,可能会影响多表连接查询。其中sc表的建表信息如下(其中包含了外键关系)。&
CREATE TABLE
'joblog'. 'sc' (
'id' int(10) unsigned NOT NULL auto_increment COMMENT 'id',
'Sno' int(10) unsigned NOT NULL default '0' COMMENT '学号',
'Cno' int(10) unsigned NOT NULL default '0' COMMENT '课程号',
'Grade' int(10) unsigned default NULL COMMENT '成绩',
PRIMARY KEY
KEY 'FK_sc_1' ('Sno'),
KEY 'FK_sc_2' ('Cno'),
CONSTRAINT 'FK_sc_1' FOREIGN KEY ('Sno') REFERENCES 'student' ('id'),
/* 外键信息 */
CONSTRAINT 'FK_sc_2' FOREIGN KEY ('Cno') REFERENCES 'course' ('id')
/* 外键信息 */
) ENGINE=InnoDB DEFAULT CHARSET=gb2312;
6.4.2& 表中的数据&
这一节中用到了3个表的数据,student表和course表的数据如6.1节中图6-2和6-4所示,但是sc表的内容变为图6-9所示的数据,其中Sno和Cno存储的分别是student表和course表中对应的主键值。&
图6-9& 本节中所用的表sc中的内容&
6.4.3& 修改持久化类&
Student对象和Course对象之间是多对多的关系。此处使用的是单向关联,仅仅建立从Student到Course的单向关联。如图6-10所示,仅有Student到Course的单向关联。&
图6-10& Student到Course类的单向关联&
为了建立Student到Course的单向关联关系,在Student.java中新加一个属性course。course属性是Set型的,可以在这个属性中加入多个Course对象,建立起关联关系。下面是加入course属性后的源代码,粗体部分为加入的代码。&
package hibernate.ch06;
import java.util.HashS
import java.util.S
public class Student
implements java.io.Serializable {
private Set course=new HashSet();
//所选课程
public Student() {
//此处省略其他的构造方法
//此处省略getter/setter访问器
//course属性的get访问器
public Set getCourse() {
//course属性的set访问器
public void setCourse(Set course) {
this.course =
持久化类Course.java和SC.java无需修改。&
6.4.4 在映射文件中加入关联信息&
在Student.hbm.xml映射配置文件中,加入Student到Course的映射信息。关于如何映射关联关系,将在第8章讲解,读者可暂时按照下面的设置,具体含义等阅读完第八章便可理解。具体代码如下。&
&set name=&course& table=&sc& lazy=&false& cascade=&save-update&&
&key column=&sno& /&
&many-to-many class=&hibernate.ch06.Course& column=&cno& /&
说明如下。&
&&&& &set&元素是和&class&元素平行的元素。&set&元素表明将要映射的字段对应着一个集合。&set&元素包含多个属性,其中:name属性用于设置映射的持久化类的属性名称,在本例中为Student表的course属性;table属性表示多对多关联关系的中间表名称,此处为sc表;cascade表示当保存或者更新Student实例时,是否保存或更新Course
&&&& &set&元素的子元素&key column=&sno& /&设定与student表关联的中间表sc的外键sno。&
&&&& &set&元素的子元素&many-to-many&用于设定多对多关系。在该元素中,class属性用于设定多对多关系中,与Student类关联的类Course类;column属性设定中间表与course表连接的外键cno。&
完整的配置文件Student.hbm.xml如下所示。&
&?xml version=&1.0&?&
&!DOCTYPE hibernate-mapping PUBLIC &-//Hibernate/Hibernate Mapping DTD 3.0//EN&
&http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd&&
&hibernate-mapping&
&class name=&hibernate.ch06.Student& table=&student& catalog=&joblog&&
&id name=&id& type=&integer&&
&column name=&id& /&
&generator class=&identity&&&/generator&
&!--映射学号--&
&property name=&sno& type=&integer&&
&column name=&Sno& not-null=&true& /&
&/property&
&!--映射姓名--&
&property name=&sname& type=&string&&
&column name=&Sname& length=&45& /&
&/property&
&!--映射系部--&
&property name=&sdept& type=&string&&
&column name=&Sdept& length=&10& /&
&/property&
&!--映射年龄--&
&property name=&sage& type=&integer&&
&column name=&Sage& /&
&/property&
&!--映射性别--&
&property name=&ssex& type=&string&&
&column name=&Ssex& length=&2& /&
&/property&
&!--映射住址--&
&property name=&saddress& type=&string&&
&column name=&Saddress& length=&45& /&
&/property&
&!--联接--&
&set name=&course& table=&sc& lazy=&false& cascade=&save-update&&
&key column=&sno& /&
&many-to-many class=&hibernate.ch06.Course& column=&cno& /&
&!--多对多--&
&/hibernate-mapping&
6.4.5& 左外连接&
左外连接(Left Outer Join)查询出左表对应的复合条件的所有记录,如查询李晓梅同学的选课信息。下面是类HQLLeftOuterJoinQuery的源代码。&
package hibernate.ch06;
import hibernate.HibernateSessionF
import java.util.I
import java.util.L
import org.hibernate.Q
import org.hibernate.S
public class HQLLeftOuterJoinQuery {
public static void main(String[] args) {
Session session=HibernateSessionFactory.currentSession();
//HQL查询语句
String hql=&from Student s left join s.course c where s.sname='李晓梅'&;
Query query=session.createQuery(hql);
//创建查询
List list=query.list();
//执行查询
Iterator it=list.iterator();
while(it.hasNext()){
Object[] obj=(Object[])it.next();
Student stu=(Student)obj[0];
Course course=(Course)obj[1];
System.out.println(&*********学生信息及其选课信息******************&);
if(course!=null){
System.out.println(stu.getSno()+&/t&+stu.getSname()+&/t&+
&课程:&+course.getCname());
System.out.println(stu.getSno()+&/t&+stu.getSname()+&/t&);
如果只用单表查询,只能从student表中查询出李晓梅的个人信息,而无法知道她的选课信息,因为选课信息存储在中间表sc中。HQL语句from Student s left join s.course c where s.sname='李晓梅'检索出了李晓梅的选课信息。&
&&&& 在HQL中使用left outer join关键字进行左外连接,outer关键字可以省略。&
&&&& s.course是Student对象中的一个属性,用来存储Student对象的选课信息。在执行查询时,将根据Student.hbm.xml中的配置生成SQL语句,并检索信息。&
&&&& 查询的结果返回一个Object[]数组,数组的第0个元素是Student对象,第1个元素是与Object[0]中对应的学生所选课的Course对象。&
HQLLeftOuterJoinQuery类在执行过程中生成的左外连接的SQL语句如下。&
Hibernate:
student0_.id as id1_0_,
course2_.id as id4_1_,
student0_.Sno as Sno1_0_,
student0_.Sname as Sname1_0_,
student0_.Sdept as Sdept1_0_,
student0_.Sage as Sage1_0_,
student0_.Ssex as Ssex1_0_,
student0_.Saddress as Saddress1_0_,
course2_.Cno as Cno4_1_,
course2_.Cname as Cname4_1_,
course2_.Ccredit as Ccredit4_1_
joblog.student student0_
left outer join
sc course1_
on student0_.id=course1_.sno
left outer join
joblog.course course2_
on course1_.cno=course2_.id
student0_.Sname='李晓梅'
Hibernate:
course0_.sno as sno1_,
course0_.cno as cno1_,
course1_.id as id4_0_,
course1_.Cno as Cno4_0_,
course1_.Cname as Cname4_0_,
course1_.Ccredit as Ccredit4_0_
sc course0_
left outer join
joblog.course course1_
on course0_.cno=course1_.id
course0_.sno=?
程序的查询结果如下。&
*********学生信息及其选课信息******************&
&&& 李晓梅&&& 课程:数据库&
*********学生信息及其选课信息******************&
&&& 李晓梅&&& 课程:操作系统&
使用如下语句将只返回Student对象。&
select s from Student s left join s.course c where s.sname='李晓梅'&
如下是只返回Student对象的部分代码。&
& & & & Session session=HibernateSessionFactory.currentSession();
//HQL查询语句
String hql=&select s from Student s left join s.course c where s.sname='李晓梅'&;
Query query=session.createQuery(hql);
//创建查询
List list=query.list();
//执行查询
Iterator it=list.iterator();
while(it.hasNext()){
Student stu=(Student)it.next();
System.out.println(&*********学生信息及其选课信息******************&);
System.out.println(stu.getSno()+&/t&+stu.getSname()+&/t&);
6.4.6& 左外抓取连接&
左外抓取连接指定在Hibernate检索数据时,采用抓取的方式,直接将数据加载到与Student对象关联的course属性中。下面是左外抓取连接的程序。&
&&&&&&& //HQL查询语句&
String hql=&select s from Student s left join fetch s.course c where s.sname='李晓梅'&;
Query query=session.createQuery(hql);
//创建查询
List list=query.list();
//执行查询
Iterator it=list.iterator();
while(it.hasNext()){
Student stu=(Student)it.next();
System.out.println(&*********学生信息及其选课信息******************&);
System.out.println(stu.getSno()+&/t&+stu.getSname()+&/t&);
&&&& 左外抓取连接使用left join fetch关键字。&
&&&& 与左外连接不同的是:左外抓取连接query.list()返回的集合中存放Student对象的引用,与之相关联的选课信息存放在course属性中。&
6.4.7& 右外连接&
HQL中使用关键字right outer join右外连接,outer关键字可以省略。右外连接与左外连接类似,不再赘述。&
6.4.8& 内连接&
内连接(Inner Join)是指两个表中指定的关键字相等的值才会出现在结果集中的一种查询方式。HQL中使用关键字inner join进行内连接,下面是使用内连接的程序。&
Session session=HibernateSessionFactory.currentSession()
//创建Session
String hql=&from Student s inner join s.course c&;
//HQL查询语句
Query query=session.createQuery(hql);
//创建查询
List list=query.list();
//执行查询
Iterator it=list.iterator();
while(it.hasNext()){
Object[] obj=(Object[])it.next();
Student stu=(Student)obj[0];
Course course=(Course)obj[1];
System.out.println(&*********学生信息及其选课信息******************&);
System.out.println(stu.getSno()+&/t&+stu.getSname()+&/t&+&课程:&+course. getCname());
&&&& HQL中使用inner join进行内连接,内连接只关联并检索那些选了课的学生信息及其选课信息,没有选课的学生不在检索结果中。&
&&&& 可以使用select s from Student s inner join s.course c只返回Student对象。&
6.4.9& 抓取内连接&
抓取内连接与内连接不同之处在于其对象的内存状态不一样。HQL中使用inner join fetch进行抓取内连接,如下程序所示。&
& & & &&Session session=HibernateSessionFactory.currentSession();
//创建Session
String hql=&select s from Student s inner join fetch s.course c&;
Query query=session.createQuery(hql);
//创建查询
List list=query.list();
//执行查询
Iterator it=list.iterator();
while(it.hasNext()){
Student stu=(Student)it.next();
System.out.println(&*********学生信息及其选课信息******************&);
System.out.println(stu.getSno()+&/t&+stu.getSname()+&/t&);
&&&& 内抓取连接使用inner join fech关键字。&
&&&& 它与内连接的区别是返回检索的list中存放的是Student对象的引用,与之相关联的选课信息存放在course属性中。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:4268818次
积分:41410
积分:41410
排名:第71名
原创:209篇
转载:2236篇
评论:450条
(10)(96)(177)(114)(86)(40)(43)(73)(15)(10)(17)(12)(6)(20)(27)(54)(71)(97)(74)(32)(2)(24)(21)(62)(60)(36)(23)(27)(46)(34)(76)(63)(121)(142)(74)(54)(120)(77)(42)(4)(12)(19)(1)(9)(15)(19)(18)(16)(31)(79)(68)> Hibernate的对象检索计策 (一) SQL左外连接检索策略
Hibernate的对象检索计策 (一) SQL左外连接检索策略
xiaoxiaoyujian2 & &
发布时间: & &
浏览:1 & &
回复:0 & &
悬赏:0.0希赛币
Hibernate的对象检索策略 (一) SQL左外连接检索策略
首先是测试表的结构:先通过hibernate将数据放入数据库,如下:  Session session = HibernateUtil.openSession();
Transaction tx=session.beginTransaction();
User u1=new User(1,"Tom",19);
User u2=new User(2,"Mike",19);
User u3=new User(3,"Jack",19);
User u4=new User(4,"Linda",19);
Order o1=new Order(1,"Tom_Order001",u1);
Order o2=new Order(2,"Tom_Order002",u1);
Order o3=new Order(3,"Mike_Order001",u2);
Order o4=new Order(4,"Jack_Order001",u3);
Order o5=new Order(5,"Linda_Order001",u4);
u1.setOrders(ArraysHelper.asSet(o1,o2));
u2.setOrders(ArraysHelper.asSet(o3));
u3.setOrders(ArraysHelper.asSet(o4));
u4.setOrders(ArraysHelper.asSet(o5));
session.save(u1);
session.save(u2);
session.save(u3);
session.save(u4);
tx.commit();====================================================数据加入之后, 看一下检索的方法。第一种是:   List userList=session.createQuery("from User as u").list();
for(User u:userList){
System.out.println(u.getOrders().iterator().next().getName());
}-运行以上方法时,Hibernate将先查询User表中的所有记录,然后根据每条记录的ID,到Order表中查询有关的记录,Hibernate将以此执行以下select语句:select * from Uselect * from Order where customer_id=1;select * from Order where customer_id=2;select * from Order where customer_id=3;select * from Order where customer_id=4;上述方法的缺点:-select语句的数目太多,需要频繁的访问数据库,会影响检索性能。如果需要查询n个User对象,那么必须执行n+1次select查询语句。这种检索策略没有利用SQL的链接查询功能。 SQL左外连接检索策略一.通过配置文件指定自动左外连接检索例如以上5条select语句完全可以通过以下1挑select语句来完成:select * from User left outer join Order on User.id = Order.Customer_id-以上select语句使用了SQL的左外连接查询功能,能够在一条select语句中查询出User表的所有记录,以及匹配的Order表的记录。在Hibernate中, 多对一的关联配置文件中可以配置使用左外连接检索策略。把Order.hbm.xml文件的&many-to-one&元素的outer-join属性设置为true,程序执行时就会自动使用左外连接检索策略。运行结果如下:通过此方法, 当运行下面的代码时:  Order order=(Order) session.get(Order.class, 1);
System.out.println(order.getName());
System.out.println(order.getUser().getName());就只会像数据库发送一条左外连接的select语句,大大降低了数据库开销。输出结果:Hibernate: select order0_.id as id1_1_1_, order0_.test_name as test2_1_1_, order0_.customer_id as customer3_1_1_, user1_.id as id1_3_0_, user1_.test_name as test2_3_0_, user1_.test_age as test3_3_0_ from test_order order0_ left outer join test_user user1_ on order0_.customer_id=user1_.id where order0_.id= Tom_Order001Tom二. 在程序中显式指定左外连接策略检索- 以下Session的方法都用于检索OID为1的User对象。session.createQuery("from User as u where u.id=1");session.createQuery("from User as u left join fetch u.orders where u.id=1");在执行第一个方法时,Hibernate会使用映射文件配置的检索策略。在执行第二个方法时,在HQL语句中显式指定左外连接检索关联的Order对象,因此会覆盖映射文件配置的检索策略。不管在User.hbm.xml文件中&set&元素的lazy属性是true还是false,Hibernate都会执行以下select语句:select * from User left outer join Order on User.id = Order.customer_id where User.id=1;
本问题标题:
本问题地址:
温馨提示:本问题已经关闭,不能解答。
暂无合适的专家
&&&&&&&&&&&&&&&
希赛网 版权所有 & &&本帖子已过去太久远了,不再提供回复功能。Hibernate HQL查询语句总结 - itshu - ITeye技术网站
Hibernate 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查询。由于HQL查询在整个Hibernate实体操作体系中的核心地位,这一节我将专门围绕HQL操作的具体技术细节进行讲解。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.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();mit();通过这种方式我们可以在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();mit();如果你是逐个章节阅读的化,那么你一定会记起我在第二部分中有关批量数据操作的相关论述中,讨论过这种操作方式,这种操作方式在Hibernate3中称为bulk delete/update,这种方式能够在很大程度上提高操作的灵活性和运行效率,但是采用这种方式极有可能引起缓存同步上的问题(请参考相关论述)。3、 属性查询:很多时候我们在检索数据时,并不需要获得实体对象所对应的全部数据,而只需要检索实体对象的部分属性所对应的数据。这时候就可以利用HQL属性查询技术,如下面程序示例:List list=session.createQuery(“select user.name from User user ”).list();for(int i=0;iSystem.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;iObject[] 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;iUser 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;iUser 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.上面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表,它们的结构如下:customerID varchar2(14)age number(10)name varchar2(20)orderID varchar2(14)order_number number(10)customer_ID varchar2(14)现在有两条HQL查询语句,分别如下:from Customer c inner join c.orders o group by c.(1)select c.ID,c.name,c.age,o.ID,o.order_number,o.customer_IDfrom Customer c inner join c.orders c group by c.(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安全漏洞
浏览 26167
浏览: 291495 次
来自: 北京
楼主好人!,网上好多都不能用!
hibernate3也可以采用OpenSessionInVie ...
试试,之前下载了lordhong的,根本就无法运行。

我要回帖

更多关于 hibernate的hql语句 的文章

 

随机推荐