补充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分别定义了命名参数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安全漏洞。
HQL是完全面向对象的查询语言,因此可以支持继承和多态等特征。
HQL查询依赖于Query类,每个Query实例对应一个查询对象,使用HQL查询按
如下步骤进行:
(1)获取Hibernate Session对象;
(2)编写HQL语句;
(3)以HQL语句作为参数,调用Session的createQuery方法创建查询对象;
(4)如果HQL语句包含参数,调用Query的setXxx方法为参数赋值;
(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);
//通过Session的createQuery方法创建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方式
当查询数据时,人们往往需要设置查询条件。在SQL或HQL语句中,查询条件常常放在where子句中。此外,Hibernate还支持Criteria查询(Criteria Query),这种查询方式把查询条件封装为一个Criteria对象。在实际应用中,使用Session的createCriteria()方法构建一个org.hibernate.Criteria实例,然后把具体的查询条件通过Criteria的add()方法加入到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() | 对应SQL的between子句 |
Restrictions.like() | 对应SQL的like子句 |
Restrictions.in() | 对应SQL的in子句 |
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(“name”, “t%”))
List list = cr.list();
Student stu = (Student)list.get(0);
或者使用另一种方式:
Criteria cr = session.createCriteria(Student.class);
cr.add(Restrictions.like(“name”, “t”, MatchMode.START))
List list = cr.list();
Student stu = (Student)list.get(0);
例2:查询学生姓名在Bill, Jack和Tom之间的所有Student对象。
String[] names = {“Bill”, “Jack”, “Tom”}
Criteria cr = session.createCriteria(Student.class);
cr.add(Restrictions.in(“name”, names))
List list = cr.list();
Student stu = (Student)list.get(0);
例3:查询学生的年龄age等于22或age为空(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(“name”, “F%”);
cr.addOrder(Order.asc(“name”));
List list = cr.list();
Student stu = (Student)list.get(0);
|
调用Order.asc的方法应是Criteria的addOrder()方法。
2.连接限制
在Criteria 查询中使用FetchMode来实现连接限制。在HQL语句中,可以通过fetch关键字来表示预先抓取(Eager fetching),如下所示:
from Group g
left join fetch g.students s
where g.name like '%2005'
可以使用Criteria的API完成同样的功能,如下所示:
Criteria cr = session.createCriteria(Group.class);
cr.setFetchMode(“students”, FetchMode.EAGER);
cr.add(Restrictions.like(“name”, “2005”, 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来完成所有的create、update、delete和load操作(包括存储过程)。
1.创建一个基于SQL的Query
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实例(SQLQuery是Query的子接口)。使用这个方法时,还需要传入查询的实体类,因此要配合SQLQuery的addEntity()方法一起使用。
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.自定义insert、update和delete语句
Hibernate3.x的映射文件中新添了<sql-insert>、<sql-update> 和<sql-delete>3个标记。可以使用这3个标记自定义自己的insert、update和delete语句,例如在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 insert和update语句中定义的字段必须和映射文件声明的属性相对应,一个都不能少。
l 在insert和update语句中,属性出现的顺序必须和映射文件中声明的顺序一致。
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(?,?,?)
如果不想在insert或update语句中包括所有属性,则可以在属性定义时,加上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
继续补充: