hibernate hql 分页查询

转自:http://my.oschina.net/lsw90/blog/61816

今天封装了自己的hibernateDao,主要是基于hql的,期间遇到一个问题,最后解决了,和大家分享分享

其他hibernate的查询,像QBE,QBC,这些就不说了,如果用hibernate还是hql最强大,也很容易上手

先上代码,这里只列出主要代码

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
/**
      * hql分页查询
      *
      * @param hql
      *            查询字符串
      * @param queryResult
      *            查询结果
      * @param values
      *            查询值
      * @return
      */
     @SuppressWarnings ( "unchecked" )
     public QueryResult hqlQueryPage( final String hql,
             final QueryResult queryResult, final Map values) {
         return hibernateTemplate.execute( new HibernateCallback() {
 
             @Override
             public QueryResult doInHibernate(Session session)
                     throws HibernateException, SQLException {
                 Query query = session.createQuery(hql).setFirstResult(
                         (queryResult.getCurrentPage().intValue() - 1 )
                                 * queryResult.getPageSize().intValue()).setMaxResults(
                         queryResult.getPageSize().intValue());
 
                 Set keys = values.keySet();
                 for (Object o : keys) {
                     query.setParameter((String)o, values.get(o));
                 }
                 queryResult.setResultList(query.list());
                 String countHql = "select count(*) " +hql;       //封装查询总记录条数
                 Long allCount = getAllCount(countHql, values);  //总记录条数
                 queryResult.setAllCount(allCount);
                 queryResult.calcuatePage(); //计算总页数
                 return queryResult;
             }
         });
     }
 
     /**
      * hql查询得到总查询数目
      *
      * @param hql
      *          查询字符串
      * @param values
      *          查询值
      * @return
      */
     @SuppressWarnings ( "unchecked" )
     public Long getAllCount( final String hql, final Map values) {
         return hibernateTemplate.execute( new HibernateCallback() {
 
             @Override
             public Object doInHibernate(Session session)
                     throws HibernateException, SQLException {
                 Query query = session.createQuery(hql);
                 Set keys = values.keySet();
                 for (Object o : keys) {
                     query.setParameter((String)o, values.get(o));
                 }
                 return query.uniqueResult();
             }
         });
     }

其中QueryResult 是我对结果集的封装,比较简单,根据个人需要还可以添加一些属性

其主要代码如下,省略了get和set方法:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package com.lsw.permission.common;
 
import java.util.List;
 
public class QueryResult implements java.io.Serializable {
 
     private static final long serialVersionUID = 1L;
     private Long allCount;      //总记录条数
     private Long allPage;       //总页数
     private Long currentPage;   //当前页数
     private Long pageSize;      //一页包含的记录条数
     private List<?> resultList;   //查询结果集
 
     public QueryResult() {
         this .currentPage = 1l;
         this .pageSize = 2l; // 默认每页显示10条记录
     }
     
     //计算总页数
     public void calcuatePage() {
         if (allCount > 0 ) {
             allPage = allCount % pageSize == 0 ? allCount / pageSize
                     : (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会根据查询语句然后确定插入的值的类型的,看看这个方法的实现吧

?
1
2
3
4
5
6
7
8
9
10
11
12
13
public Query setParameter(String name, Object val) throws HibernateException {
         if (val == null ) {
             Type type = parameterMetadata.getNamedParameterExpectedType( name );
             if ( type == null ) {
                 type = Hibernate.SERIALIZABLE;
             }
             setParameter( name, val, type );
         }
         else {
             setParameter( name, val, determineType( name, val ) );
         }
         return this ;
     }

其实最后也是调用这个方法:

?
1
public Query setParameter(String name, Object val, Type type);

现数据库中有三张表,角色,用户,角色-用户表;

其中角色-用户表java代码为:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class RoleInUser implements java.io.Serializable{
 
     
 
     private static final long serialVersionUID = 1L;
 
     @Id
 
     @ManyToOne
 
     @JoinColumn (name = "user_id" )
 
     private User user;
 
     @Id
 
     @ManyToOne
 
     @JoinColumn (name = "role_id" )
 
     private Role role;
 
     @Column (name = "remark" , nullable = true , length = 100 , columnDefinition = "varchar(100)" )
 
     private String remark;
 
}

现在已知用户,需到数据库查询用户拥有哪些角色,我起初写的查询语句为:

?
1
2
3
4
String hql = "from Role r where r.roleId in (select riu.role from RoleInUser riu where riu.user = :user)" ;
         Map<String, Object> values = new HashMap<String, Object>();
         values.put( "user" , user.getUserId());
         roleDao.hqlQueryPage(hql, queryResult, values);

执行查询,却一直查询不到,最后一直做测试,原来发现是hibernate设置值进查询语句出现的问题,根据上述查询语句,hibernate会将:user设置为User类型,而不是想要的整型,请仔细看代码的变化,最后将查询语句修改为 

?
1
2
3
4
String hql = "from Role r where r.roleId in (select riu.role from RoleInUser riu where riu.user.userId = :userId)" ;
         Map<String, Object> values = new HashMap<String, Object>();
         values.put( "userId" , user.getUserId());
         roleDao.hqlQueryPage(hql, queryResult, values);

解决问题。

总结,hql是面向对象的查询语言,与我们平时用的关系型数据库语言不一样,需仔细,多看看hibernate的文档和源码


http://bluesnowsoft.com 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值