由于项目需求,所以近期开始学习HQL。
先介绍一下HQL吧,摘自百科:
Criteria查询对查询条件进行了面向对象封装,符合编程人员的思维方式,不过HQL(Hibernate Query
Language)查询提供了更加丰富的和灵活的查询特性,因此Hibernate将HQL查询方式立为官方推荐的标准查询方式,HQL查询在涵盖
Criteria查询的所有功能的前提下,提供了类似标准SQL语句的查询方式,同时也提供了更加面向对象的封装。
HQL学习笔记:
1、
一次检索多个属性:
List list = session.createQuery("select user.name,user.age form User user").list();
通过list.get()返回的为Object[]数组,从中取出name和age
循环list
{
Object[] obj = (Object[])list.get(i);
}
2、
HQL提供动态构造实例的功能,对平面数据进行封装
。使其更加符合面向对象的风格。
这个封装确实不错,可以把查出来的数据直接对象化。
List list = session.createQuery("select new User(user.name,user.age) from User user").list();
循环list
{
User user = (User)list.get(i);
user.getName();
user.getAge();
}
但是,返回的user对象,仅仅只是一个普通的java对象而已,除了查询结果值以外。其他的属性都为null(包括主键id),也就是说不能
通过session对象对此对象执行持久化更新操作
。
我的理解:查出来的东西也就是个临时对象吧,不能update,用完也就没了。
如果你想查出user的等级(lv)
但是实体类中是按照经验(exp)计算出等级的(User类中没有lv的属性),那么不必担心,你可以直接查出user.exp,即"select new User(user.name,user.age,user.exp) from User user"
然后占用exp属性,就是暂时占用你的exp属性来充当lv(前提是类型相同)
user.setExp(user.lv(user.getExp));
前台就可以通过${u.exp}获得等级了。
没必要再去增加lv属性。
List list=session.createQuery("select new User(user.name,user.age) from User user ").list();
for循环
{
User user=(User)list.get(i);
user.setName(“gam”);
session.saveOrUpdate(user);
//这里将会实际执行一个save操作,而不会执行update操作,因为这个User对象的 id属性为null,Hibernate会把它作为一个自由对象(请参考持久化对象状态部分的论述),因此会对它执行save操作。
}
注意
a、
如果使用到了“select new User(user.name,user.age) from User user”这种查询方式
那么必须在User类中实现User的构造函数
<构造>
public User(String name,int age)
{
this.name=name;
this.age=age;
}
“new User(user.name,user.age) ” 这里写的有什么,构造就要有什么样的参数!
b、
如果User有父类,也可以在“new User(user.name,user.age)”这里面调用父类的属性,但是记得在写user构造的同时也要写父类中的构造.
即:“select new User(user.name
,user.age) from User user” (name是Person的属性
,age是User的属性,User extends Person)
<构造>
User类:
public User(Stinrg name,int age)
{
super(name);
this.age=age;
}
Person类:
public Person(String name)
{
this.name=name;
}
另外:
User玩家下有一个公司属性company,company有自己的id,那么可以这样建立查询条件
select user.name,user.age from User user where user.company.id='1'
;
3、
分组与排序order by
排序方式:asc和desc(升序和降序)
from User user order by user.nage asc,user.age desc;
4、
参数绑定
A)、按参数名称绑定:
在HQL语句中定义命名参数要用”:”开头,形式如下:
Query query=session.createQuery("from User user where user.name=:customername and user.age=:customerage ”);
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);
在实际开发中,提倡使用按名称绑定,因为可提供非常好的可读性和可维护性。
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)、 使用绑定参数的优势:
1)、可以利用数据库实施性能优化,因为对Hibernate来说在底层使用的是PrepareStatement来完成查询,因此对于语法相同参数不同的SQL语句,可以充分利用预编译SQL语句缓存,从而提升查询效率。
2)、 可以防止SQL Injection安全漏洞的产生(俗说的"SQL注入"):
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安全漏洞。
我学的还不够深入,希望哪位高手给我指点指点。如果有错,请大家指出,谢谢。