文档章节

hibernate hql 分页查询

peanutmain
 peanutmain
发布于 2012/06/10 19:58
字数 1252
阅读 14371
收藏 3

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

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

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

/**
	 * 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方法:

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语句:

"from User user where user.name='"+name+"' and user.password='"+password+"'"

这个HQL语句从逻辑上来说是没有任何问题的,这个登录验证功能在一般情况下也是会正确完成的,但是如果在登录时在用户名中输入”zhaoxin' or 'x'='x”,这时如果使用简单的HQL语句的字符串拼装,就会生成如下的HQL语句:

"from User user where user.name='lsw' or 'x'='x' and user.password='admin'";

显然这条HQL语句的where字句将会永远为真,而使用户口令的作用失去意义,这就是SQL Injection攻击的基本原理。

而使用绑定参数方式,就可以妥善处理这问题,当使用绑定参数时,会得到下面的HQL语句:

from User user where user.name='lsw'' or ''x''=''x'' ' and user.password='admin';

由此可见使用绑定参数会将用户名中输入的单引号解析成字符串(如果想在字符串中包含单引号,应使用重复单引号形式),所以参数绑定能够有效防止SQL Injection安全漏洞

说说我遇到的问题吧,主要是用到

public Query setParameter(String name, Object val) throws HibernateException;

这个方法,hibernate会根据查询语句然后确定插入的值的类型的,看看这个方法的实现吧

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;
	}

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

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

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

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

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;

}

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

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类型,而不是想要的整型,请仔细看代码的变化,最后将查询语句修改为 

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的文档和源码

 

 

© 著作权归作者所有

peanutmain

peanutmain

粉丝 13
博文 21
码字总数 12061
作品 0
成都
程序员
私信 提问
hibernate hql查询(需完善)

使用HQL需要四步 得到Session 编写HQL语句 创建Query对象(Query接口是HQL 查询接口。它提供了各种的查询功能) 执行查询,得到结果 sessionFactory =new Configuration().configure().buil...

zdatbit
2016/03/10
48
0
第一篇,整体架构hibernate dao篇

对于架构,我的目标是简单,好用,写少量的代码。 到目前为止,我的目标基本达到了。 目前架构是struts2+spring3+hibernate3,大量使用注解,尽可能少的xml配置文件。 典型的MVC架构。 1、先...

yeshujun
2012/12/29
643
4
学习hibernate(八) -- HQL查询语句

HQL语句 HQL(Hibernate Query Language)提供更加丰富灵活、更为强大的查询能力。 可设定WHERE 可进行投影查询 可分页 可分组 可做连接查询 有聚合函数 支持子查询 可动态绑定参数 先看一个H...

杰克鹏仔
2016/04/11
133
0
Hibernate查询技术之HQL语句

1、session中的get( )和load( )方法来查询对象。但其查询功能有限。 2、HQL查询方式 使用传统的JDBC API来查询数据,需要编写复杂的SQL语句,然后还要将查询结果以对象的形式进行封装,放到集...

大黄有故事
2016/10/30
0
0
Hibernate 检索查询的几种方式(HQL,QBC,本地SQL,集成Spring等)

1.非集成Spring Hibernate的检索方式,主要有以下五种。 1.导航对象图检索方式。(根据已经加载的对象,导航到其他对象。) 2.OID检索方式。(按照对象的OID来检索对象。) 3.HQL检索方式。(...

长平狐
2013/01/06
2.2K
0

没有更多内容

加载失败,请刷新页面

加载更多

最简单的获取相机拍照的图片

  import android.content.Intent;import android.graphics.Bitmap;import android.os.Bundle;import android.os.Environment;import android.provider.MediaStore;import andr......

MrLins
今天
5
0
说好不哭!数据可视化深度干货,前端开发下一个涨薪点在这里~

随着互联网在各行各业的影响不断深入,数据规模越来越大,各企业也越来越重视数据的价值。作为一家专业的数据智能公司,个推从消息推送服务起家,经过多年的持续耕耘,积累沉淀了海量数据,在...

个推
今天
8
0
第三方支付-返回与回调注意事项

不管是支付宝,微信,还是其它第三方支付,第四方支付,支付机构服务商只要涉及到钱的交易都要进行如下校验,全部成功了才视为成功订单 1.http请求是否成功 2.校验商户号 3.校验订单号及状态...

Shingfi
今天
4
0
简述Java内存分配和回收策略以及Minor GC 和 Major GC(Full GC)

内存分配: 1. 栈区:栈可分为Java虚拟机和本地方法栈 2. 堆区:堆被所有线程共享,在虚拟机启动时创建,是唯一的目的是存放对象实例,是gc的主要区域。通常可分为两个区块年轻代和年老代。更...

DustinChan
今天
6
0
Excel插入批注:可在批注插入文字、形状、图片

1.批注一直显示:审阅选项卡-------->勾选显示批注选项: 2.插入批注快捷键:Shift+F2 组合键 3.在批注中插入图片:鼠标右键点击批注框的小圆点【重点不可以在批注文本框内点击】----->调出批...

东方墨天
今天
6
1

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部