今天封裝了本身的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的文檔和源碼