hibernate hql 分頁查詢

今天封裝了本身的hibernateDao,主要是基於hql的,期間遇到一個問題,最後解決了,和你們分享分享java

其餘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語句緩存,從而提高查詢效率。session

       2.能夠防止SQL Injection安全漏洞的產生:
SQL Injection是一種專門針對SQL語句拼裝的攻擊方式,好比對於咱們常見的用戶登陸,在登陸界面上,用戶輸入用戶名和口令,這時登陸驗證程序可能會生成以下的HQL語句:ide

"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的文檔和源碼

相關文章
相關標籤/搜索