HQL语言学习(二)

补充1

 

  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分别定义了命名参数customernamecustomerage,然后用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()方法:

 

  在HibernateHQL查询中可以通过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安全漏洞。

 

HQL是完全面向对象的查询语言,因此可以支持继承和多态等特征。 

HQL查询依赖于Query类,每个Query实例对应一个查询对象,使用HQL查询按 

如下步骤进行: 

(1)获取Hibernate Session对象; 

(2)编写HQL语句; 

(3)HQL语句作为参数,调用SessioncreateQuery方法创建查询对象; 

(4)如果HQL语句包含参数,调用QuerysetXxx方法为参数赋值; 

(5)调用Query对象的list等方法遍历查询结果。 

查询示例: 

public class HqlQuery 

      public static void main(String[] args) throws Exception { 

         HqlQuery mgr = new HqlQuery(); 

         //调用查询方法 

         mgr.findPersons(); 

         //调用第二个查询方法 

         mgr.findPersonByHappenDate(); 

         HibernateUtil.sessionFactory.close(); 

     } 

     //第一个查询方法 

      private void findPersons() { 

         //获得Hibernate Session 

Session sess = HibernateUtil.currentSession(); 

         //开始事务 

         Transaction tx = sess.beginTransaction(); 

         //HQL语句创建Query对象 

         //执行setString方法为HQL语句的参数赋值 

         //Query调用list方法访问查询的全部实例 

         List p1 = sess.createQuery("from Person p where o.myEvents.title = : 

             eventTitle").setString("eventTitle", "很普通事情").list(); 

         //遍历查询的全部结果 

         for (Iterator pit = p1.iterator(); pit.haxNext(); ) 

          { 

             Person p = (Person)pit.next(); 

             System.out.println(p.getName()); 

         } 

         //提交事务 

         tx.commit(); 

         HibernateUtil.closeSession(); 

     } 

//第二个查询方法 

      private void findPersonByHappenDate() throws Exception { 

         Session sess = HibernateUtil.currentSession(); 

         Transaction tx = sess.beginTransaction(); 

         //解析出Date对象 

         SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); 

         Date start = sdf.parse("2007-11-27"); 

         System.out.println("系统开始通过日期查找人" + start); 

         //通过SessioncreateQuery方法创建Query对象 

         //设置参数 

         //返回结果集 

         List pl = sess.createQuery( 

             "from Person p where p.myEvents.happenDate between :firstDate 

             and :endDate") 

                         .setDate("firstDate", start) 

                         .setDate("endDate", new Date()) 

                         .list(); 

         //遍历结果集 

         for (Iterator pit = pl.iterator(); pit.hasNext(); ) 

          { 

             Person p = (Person)pit.next(); 

             System.out.println(p.getName()); 

         } 

         tx.commit(); 

         HibernateUtil.closeSession(); 

     } 

 

 

 

 

 

 

 

 

 

补充2

9.1.2  Criteria Query方式

当查询数据时,人们往往需要设置查询条件。在SQLHQL语句中,查询条件常常放在where子句中。此外,Hibernate还支持Criteria查询(Criteria Query),这种查询方式把查询条件封装为一个Criteria对象。在实际应用中,使用SessioncreateCriteria()方法构建一个org.hibernate.Criteria实例,然后把具体的查询条件通过Criteriaadd()方法加入到Criteria实例中。这样,程序员可以不使用SQL甚至HQL的情况下进行数据查询,如例程9-1所示。

例程9-1  Criteria应用实例

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

Criteria cr = session.createCriteria(Student.class); //生成一个Criteria对象

cr.add(Restrictions.eq("name", "Bill"));//等价于where name=Bill

List list = cr.list();

Student stu = (Student)list.get(0);

System.out.println(stu.getName());

1.常用的查询限制方法

在例程9-1中,Restrictions.eq()方法表示equal,即等于的情况。Restrictions类提供了查询限制机制。它提供了许多方法,以实现查询限制。这些方法及其他一些criteria常用查询限制方法列于表9-1中。

9-1  Criteria Query常用的查询限制方法

方    法

说    明

Restrictions.eq()

equal=

Restrictions.allEq()

参数为Map对象,使用key/value进行多个等于的对比,相当于多个Restrictions.eq()的效果

Restrictions.gt()

greater-than, >

Restrictions.lt()

less-than, <

Restrictions.le()

less-equal, <=

Restrictions.between()

对应SQLbetween子句

Restrictions.like()

对应SQLlike子句

Restrictions.in()

对应SQLin子句

Restrictions.and()

and关系

Restrictions.or()

or关系

Restrictions.isNull()

判断属性是否为空,为空返回true,否则返回false

Restrictions.isNotNull()

Restrictions.isNull()相反

Order.asc()

根据传入的字段进行升序排序

Order.desc()

根据传入的字段进行降序排序

MatchMode.EXACT

字符串精确匹配,相当于“like 'value'

MatchMode.ANYWHERE

字符串在中间位置,相当于“like '%value%'

MatchMode.START

字符串在最前面的位置,相当于“like 'value%'

MatchMode.END

字符串在最后面的位置,相当于“like '%value'

1:查询学生名字以t开头的所有Student对象。

Criteria cr = session.createCriteria(Student.class);

cr.add(Restrictions.like(namet%))

List list = cr.list();

Student stu = (Student)list.get(0);

或者使用另一种方式:

Criteria cr = session.createCriteria(Student.class);

cr.add(Restrictions.like(namet, MatchMode.START))

List list = cr.list();

Student stu = (Student)list.get(0);

2:查询学生姓名在Bill, JackTom之间的所有Student对象。

String[] names = {BillJackTom}

Criteria cr = session.createCriteria(Student.class);

cr.add(Restrictions.in(name, names))

List list = cr.list();

Student stu = (Student)list.get(0);

3:查询学生的年龄age等于22age为空(null)的所有Student对象。

Criteria cr = session.createCriteria(Student.class);

cr.add(Restrictions.eq(age, new Integer(22));

cr.add(Restrictions.isNull(age));

List list = cr.list();

Student stu = (Student)list.get(0);

4:查询学生姓名以字母F开头的所有Student对象,并按姓名升序排序。

Criteria cr = session.createCriteria(Student.class);

cr.add(Restrictions.like(nameF%);

cr.addOrder(Order.asc(name));

List list = cr.list();

Student stu = (Student)list.get(0);

Tips

 

调用Order.asc的方法应是CriteriaaddOrder()方法。

2.连接限制

Criteria 查询中使用FetchMode来实现连接限制。在HQL语句中,可以通过fetch关键字来表示预先抓取(Eager fetching),如下所示:

from Group g

left join fetch g.students s

where g.name like '%2005'

可以使用CriteriaAPI完成同样的功能,如下所示:

Criteria cr = session.createCriteria(Group.class);

cr.setFetchMode(students, FetchMode.EAGER);

cr.add(Restrictions.like(name2005, MatchMode.END))

List list = cr.list();

以上两种方式编写的代码,都使用相同的SQL语句完成它们的功能,如下所示:

select g.*, s.* from Group g

left outer join Student s

on g.id = s.group_id

where g.name like '%2005'

9.1.3  Native SQL查询

本地SQL查询(Native SQL Query)指的是直接使用本地数据库(如Oracle)的SQL语言进行查询。它能够扫清你把原来直接使用SQL/JDBC 的程序迁移到基于 Hibernate应用的道路上的障碍。

Hibernate3允许你使用手写的SQL来完成所有的createupdatedeleteload操作(包括存储过程)。

1.创建一个基于SQLQuery

Native SQL查询是通过SQLQuery接口来控制的,它是通过调用Session.createSQLQuery()方法来获得的,例如:

String sql = "select {s.*} from t_student s where s.age>22";

SQLQuery slqQuery = session.createSQLQuery(sql);

sqlQuery.addEntity("s", Student.class);

List list = sqlQuery.list();

for (int i=0;list.size();i++) {

Student stu = (Student)list.get(i);

System.out.println(stu.getAge() +" "+ stu.getName());

}

createSQLQuery(String sql)利用传入的SQL参数构造一个SQLQuery实例(SQLQueryQuery的子接口)。使用这个方法时,还需要传入查询的实体类,因此要配合SQLQueryaddEntity()方法一起使用。

addEntity()方法是将实体类别与别名联系在一起的方法,此方法的定义如下:

public SQLQuery addEntity(String alias, Class entityClass)

{}号用来引用数据表的别名,例如以上代码中{s.*}表示使用s来作为t_student表的别名。

2.命名SQL查询

HQL的命名查询相似,也可以将本地的SQL查询语句定义在映射文件中,然后像调用一个命名HQL查询一样直接调用命名SQL查询。

例如在Student.hbm.xml中定义一个命名SQL查询,如下所示:

<hibernate-mapping>

<class name="Student" table="student" lazy="false">

……

</class>

<sql-query name="QueryStudents">

<![CDATA[

             select {s.*} from t_student s where s.age>22

]]>

<return alias="s" class="Student"/>

</sql-query>

</hibernate-mapping>

<sql-query>元素是<hibernate-mapping>元素的一个子元素。利用<sql-query>元素的子元素<return>指定别名与实体类相关联。配合映射文件中的定义,编写如下代码来调用这个命名SQL查询:

Query query = session.getNamedQuery(QueryStudents);

List list = query.list();

for (int i=0;list.size();i++) {

Student stu = (Student)list.get(i);

System.out.println(stu.getAge() + “ ”+ stu.getName());

}

也可以在命名查询中设定查询参数,如下所示:

……

<sql-query name=QueryStudents>

    <![CDATA[

        select {s.*} from t_student s where s.age>:age

    ]]>

    <return alias=s” class=Student/>

</sql-query>

..

编写如下代码来调用这个命名SQL查询,并且把查询中定义的参数传入:

Query query = session.getNamedQuery(QueryStudents);

query.setInteger(age,22);

List list = query.list();

for (int i=0;list.size();i++) {

Student stu = (Student)list.get(i);

System.out.println(stu.getAge() + “ ”+ stu.getName());

}

3.自定义insertupdatedelete语句

Hibernate3.x的映射文件中新添了<sql-insert><sql-update> <sql-delete>3个标记。可以使用这3个标记自定义自己的insertupdatedelete语句,例如在Student.hbm.xml中定义这些语句如下:

<hibernate-mapping>

<class name="Student" table="student" lazy="false">

<id name="id" unsaved-value="null" type="string" column="id">

    <generator class="uuid.hex"/>

<property name="name" type="string" />

<property name="age" type="int" />

<sql-insert> <!--insert语句-->

    insert into t_student(name, age, id) values(?,?,?)

    </sql-insert>

    <sql-update> <!--update语句-->

    update t_student set name=?, age=? where id=?

    </sql-update>

    <sql-delete> <!--delete语句-->

        delete from t_student where id=?

</sql-delete>

</class>

</hibernate-mapping>

对于上述文件中自定义的SQL语句,要注意以下几点。

l         insertupdate语句中定义的字段必须和映射文件声明的属性相对应,一个都不能少。

l         insertupdate语句中,属性出现的顺序必须和映射文件中声明的顺序一致。

l         insert语句中,主键id总是放在最后。

在程序中实现以上自定义的insert语句如下:

……

Student stu = new Student();

stu.setName(Bill);

stu.setAge(22);

session.save(stu);

运行上述程序,控制台显示的信息如下:

Hibernate: insert into t_student(name,age,id) values(?,?,?)

如果不想在insertupdate语句中包括所有属性,则可以在属性定义时,加上insert="false"update="false",如下所示:

<property name=name” type=string” insert=false” update=false” />

    <sql-insert>  insert into t_student(age, id) values(?,?)  </sql-insert>

<sql-update> update t_student set age=? where id=?  </sql-update>

实例:

 


原文地址:

http://www.cnblogs.com/wycnblogs/articles/2845814.html


继续补充:

http://wenku.baidu.com/view/f12f9f0b79563c1ec5da7190.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值