今天封装了自己的hibernateDao,主要是基于hql的,期间遇到一个问题,最后解决了,和大家分享分享
其他hibernate的查询,像QBE,QBC,这些就不说了,如果用hibernate还是hql最强大,也很容易上手
先上代码,这里只列出主要代码
12 |
@SuppressWarnings ( "unchecked" ) |
13 |
public QueryResult
hqlQueryPage( final String
hql, |
14 |
final QueryResult
queryResult, final Map
values) { |
15 |
return hibernateTemplate.execute( new HibernateCallback()
{ |
18 |
public QueryResult
doInHibernate(Session session) |
19 |
throws HibernateException,
SQLException { |
20 |
Query
query = session.createQuery(hql).setFirstResult( |
21 |
(queryResult.getCurrentPage().intValue()
- 1 ) |
22 |
*
queryResult.getPageSize().intValue()).setMaxResults( |
23 |
queryResult.getPageSize().intValue()); |
25 |
Set
keys = values.keySet(); |
26 |
for (Object
o : keys) { |
27 |
query.setParameter((String)o,
values.get(o)); |
29 |
queryResult.setResultList(query.list()); |
30 |
String
countHql = "select
count(*) " +hql; |
31 |
Long
allCount = getAllCount(countHql, values); |
32 |
queryResult.setAllCount(allCount); |
33 |
queryResult.calcuatePage(); |
48 |
@SuppressWarnings ( "unchecked" ) |
49 |
public Long
getAllCount( final String
hql, final Map
values) { |
50 |
return hibernateTemplate.execute( new HibernateCallback()
{ |
53 |
public Object
doInHibernate(Session session) |
54 |
throws HibernateException,
SQLException { |
55 |
Query
query = session.createQuery(hql); |
56 |
Set
keys = values.keySet(); |
57 |
for (Object
o : keys) { |
58 |
query.setParameter((String)o,
values.get(o)); |
60 |
return query.uniqueResult(); |
其中QueryResult 是我对结果集的封装,比较简单,根据个人需要还可以添加一些属性
其主要代码如下,省略了get和set方法:
01 |
package com.lsw.permission.common; |
03 |
import java.util.List; |
05 |
public class QueryResult implements java.io.Serializable
{ |
07 |
private static final long serialVersionUID
= 1L; |
08 |
private Long
allCount; |
10 |
private Long
currentPage; |
11 |
private Long
pageSize; |
12 |
private List<?>
resultList; |
14 |
public QueryResult()
{ |
15 |
this .currentPage
= 1l; |
20 |
public void calcuatePage()
{ |
22 |
allPage
= allCount % pageSize == 0 ?
allCount / pageSize |
23 |
:
(allCount / pageSize + 1 ); |
分页方法中的values 是参数值
在这里说说使用使用绑定参数的优势:
1.可以利用数据库实施性能优化,因为对Hibernate来说在底层使用的是PrepareStatement来完成查询,因此对于语法相同参数不同的SQL语句,可以充分利用预编译SQL语句缓存,从而提升查询效率。
2.可以防止SQL Injection安全漏洞的产生:
SQL Injection是一种专门针对SQL语句拼装的攻击方式,比如对于我们常见的用户登录,在登录界面上,用户输入用户名和口令,这时登录验证程序可能会生成如下的HQL语句:
1 |
"from
User user where user.name='" +name+ "'
and user.password='" +password+ "'" |
这个HQL语句从逻辑上来说是没有任何问题的,这个登录验证功能在一般情况下也是会正确完成的,但是如果在登录时在用户名中输入”zhaoxin' or 'x'='x”,这时如果使用简单的HQL语句的字符串拼装,就会生成如下的HQL语句:
1 |
"from
User user where user.name='lsw' or 'x'='x' and user.password='admin'" ; |
显然这条HQL语句的where字句将会永远为真,而使用户口令的作用失去意义,这就是SQL Injection攻击的基本原理。
而使用绑定参数方式,就可以妥善处理这问题,当使用绑定参数时,会得到下面的HQL语句:
1 |
from
User user where user.name= 'lsw' '
or ' 'x' '=' 'x' '
' and
user.password= 'admin' ; |
由此可见使用绑定参数会将用户名中输入的单引号解析成字符串(如果想在字符串中包含单引号,应使用重复单引号形式),所以参数绑定能够有效防止SQL Injection安全漏洞
说说我遇到的问题吧,主要是用到
1 |
public Query
setParameter(String name, Object val) throws HibernateException; |
这个方法,hibernate会根据查询语句然后确定插入的值的类型的,看看这个方法的实现吧
01 |
public Query
setParameter(String name, Object val) throws HibernateException
{ |
03 |
Type
type = parameterMetadata.getNamedParameterExpectedType( name ); |
05 |
type
= Hibernate.SERIALIZABLE; |
07 |
setParameter(
name, val, type ); |
10 |
setParameter(
name, val, determineType( name, val ) ); |
其实最后也是调用这个方法:
1 |
public Query
setParameter(String name, Object val, Type type); |
现数据库中有三张表,角色,用户,角色-用户表;
其中角色-用户表java代码为:
01 |
public class RoleInUser implements java.io.Serializable{ |
05 |
private static final long serialVersionUID
= 1L; |
11 |
@JoinColumn (name
= "user_id" ) |
19 |
@JoinColumn (name
= "role_id" ) |
23 |
@Column (name
= "remark" ,
nullable = true ,
length = 100 ,
columnDefinition = "varchar(100)" ) |
25 |
private String
remark; |
现在已知用户,需到数据库查询用户拥有哪些角色,我起初写的查询语句为:
1 |
String
hql = "from
Role r where r.roleId in (select riu.role from RoleInUser riu where riu.user = :user)" ; |
2 |
Map<String,
Object> values = new HashMap<String,
Object>(); |
3 |
values.put( "user" ,
user.getUserId()); |
4 |
roleDao.hqlQueryPage(hql,
queryResult, values); |
执行查询,却一直查询不到,最后一直做测试,原来发现是hibernate设置值进查询语句出现的问题,根据上述查询语句,hibernate会将:user设置为User类型,而不是想要的整型,请仔细看代码的变化,最后将查询语句修改为
1 |
String
hql = "from
Role r where r.roleId in (select riu.role from RoleInUser riu where riu.user.userId = :userId)" ; |
2 |
Map<String,
Object> values = new HashMap<String,
Object>(); |
3 |
values.put( "userId" ,
user.getUserId()); |
4 |
roleDao.hqlQueryPage(hql,
queryResult, values); |
解决问题。
总结,hql是面向对象的查询语言,与我们平时用的关系型数据库语言不一样,需仔细,多看看hibernate的文档和源码