數據庫查詢語言(一)---HQL(Hibernate Query Language)


HQL(Hibernate Query Language)提供更加豐富靈活、更爲強大的查詢能力;java

HQL更接近SQL語句查詢語法;數據庫


[select/delete/update…][from…][where…][group by…][having…][order by…]編程

  • 中文名緩存

  • 查詢語言安全

  • 外文名性能優化

  • Hibernate Query Languagesession

  • 縮    寫ide

  • hql函數

  • 特    點性能

  • 對查詢條件進行了面向對象封裝

  • 接    近

  • SQL語句查詢語法

定義

編輯

Criteria(標準)查詢對查詢條件進行了面向對象封裝,符合編程人員的思惟方式,不過HQL(Hibernate Query Language)查詢提供了更加豐富的和靈活的查詢特性,所以Hibernate將HQL查詢方式立爲官方推薦的標準查詢方式,HQL查詢在涵蓋Criteria查詢的全部功能的前提下,提供了相似標準SQL語句的查詢方式,同時也提供了更加面向對象的封裝。完整的HQL語句形式以下: Select/update/delete…… from …… where …… group by …… having …… order by …… asc/desc 其中的update/delete爲Hibernate3中所新添加的功能,可見HQL查詢很是相似於標準SQL查詢。因爲HQL查詢在整個Hibernate實體操做體系中的核心地位,下一節我將專門圍繞HQL操做的具體技術細節進行講解。

用法

編輯

實體查詢

有關實體查詢技術,其實咱們在先前已經有屢次涉及,好比下面的例子:String hql=」from User user 」; List list=session.CreateQuery(hql).list(); 上面的代碼執行結果是,查詢出User實體對象所對應的全部數據,並且將數據封裝成User實體對象,而且放入List中返回。這裏須要注意的是,Hibernate的實體查詢存在着對繼承關係的斷定,好比咱們前面討論映射實體繼承關係中的Employee實體對象,它有兩個子類分別是HourlyEmployee,SalariedEmployee,若是有這樣的HQL語句:「from Employee」,當執行檢索時Hibernate會檢索出全部Employee類型實體對象所對應的數據(包括它的子類HourlyEmployee,SalariedEmployee對應的數據)。由於HQL語句與標準SQL語句類似,因此咱們也能夠在HQL語句中使用where字句,而且能夠在where字句中使用各類表達式,比較操做符以及使用「and」,」or」鏈接不一樣的查詢條件的組合。看下面的一些簡單的例子:

from User user where user age=20;

from User user where user age between 20 and 30;

from User user where user age in(20,30);

from User user where user name is null;

from User user where user name like ‘%zx%’;

from User user where (user age%2)=1;

from User user where user age=20 and user name like ‘%zx%’;

實體的更新和刪除

在繼續講解HQL其餘更爲強大的查詢功能前,咱們先來說解如下利用HQL進行實體更新和刪除的技術。這項技術功能是Hibernate3的新加入的功能,在Hibernate2中是不具有的。好比在Hibernate2中,若是咱們想將數據庫中全部18歲的用戶的年齡所有改成20歲,那麼咱們要首先將年齡在18歲的用戶檢索出來,而後將他們的年齡修改成20歲,最後調用Session update()語句進行更新。在Hibernate3中對這個問題提供了更加靈活和更具效率的解決辦法,以下面的代碼:

Transaction trans=session beginTransaction();

String hql=」update User user set user age=20 where user age=18」;

Query queryupdate=session createQuery(hql);

int ret=queryupdate executeUpdate();

trans commit();

經過這種方式咱們能夠在Hibernate3中,一次性完成批量數據的更新,對性能的提升是至關的可觀。一樣也能夠經過相似的方式來完成delete操做,以下面的代碼:

Transaction trans=session beginTransaction();

String hql=」delete from User user where user age=18」;

Query queryupdate=session createQuery(hql);

int ret=queryupdate executeUpdate();

trans commit();

若是你是逐個章節閱讀的話,那麼你必定會記起我在第二部分中有關批量數據操做的相關論述中,討論過這種操做方式,這種操做方式在Hibernate3中稱爲bulk delete/update,這種方式可以在很大程度上提升操做的靈活性和運行效率,可是採用這種方式極有可能引發緩存同步上的問題(請參考相關論述)。

屬性查詢

不少時候咱們在檢索數據時,並不須要得到實體對象所對應的所有數據,而只須要檢索實體對象的部分屬性所對應的數據。這時候就能夠利用HQL屬性查詢技術,以下面程序示例:

List list=session createQuery(「select user name from User user 」)

list();

for(int i=0;i<list.size();i++){

System out println(list get(i));

}

咱們只檢索了User實體的name屬性對應的數據,此時返回的包含結果集的list中每一個條目都是String類型的name屬性對應的數據。咱們也能夠一次檢索多個屬性,以下面程序:

List list=session createQuery(「select user name,user age from User user 」)

list();

for(int i=0;i<list size();i++){

Object[] obj=(Object[])

list get(i);

System out println(obj[0]);

System out println(obj[1]);

}

此時返回的結果集list中,所包含的每一個條目都是一個Object[]類型,其中包含對應的屬性數據值。做爲當今咱們這一代深受面向對象思想影響的開發人員,可能會以爲上面返回Object[]不夠符合面向對象風格,這時咱們能夠利用HQL提供的動態構造實例的功能對這些平面數據進行封裝,以下面的程序代碼:

List list=session createQuery(「select new User(user name,user age) from User user 」)

list();

for(int i=0;i<list size();i++){

User user=(User)list get(i);

System out println(user getName());

System out println(user getAge());

}

這裏咱們經過動態構造實例對象,對返回結果進行了封裝,使咱們的程序更加符合面向對象風格,可是這裏有一個問題必須注意,那就是這時所返回的User對象,僅僅只是一個普通的Java對象而以,除了查詢結果值以外,其它的屬性值都爲null(包括主鍵值id),也就是說不能經過Session對象對此對象執行持久化的更新操做。以下面的代碼:

List list=session createQuery(「select new User(user name,user age) from User user 」)

list();

for(int i=0;i<list size();i++){

User user=(User)list get(i);

user setName(「gam」);

session saveOrUpdate(user);//這裏將會實際執行一個save操做,而不會執行update操做,由於這個User對象的id屬性爲null,Hibernate會把它做爲一個自由對象(請參考持久化對象狀態部分的論述),所以會對它執行save操做。

}

分組與排序

A、Order by子句

與SQL語句類似,HQL查詢也能夠經過order by子句對查詢結果集進行排序,而且能夠經過asc或者desc關鍵字指定排序方式,以下面的代碼: from User user order by user name asc,user age desc; 上面HQL查詢語句,會以name屬性進行升序排序,以age屬性進行降序排序,並且與SQL語句同樣,默認的排序方式爲asc,即升序排序。

B、Group by子句與統計查詢

在HQL語句中一樣支持使用group by子句分組查詢,還支持group by子句結合彙集函數的分組統計查詢,大部分標準的SQL彙集函數均可以在HQL語句中使用,好比:count(),sum(),max(),min(),avg()等。以下面的程序代碼:

String hql=」select count(user),user age from User user group by user age having count(user)>10 」;

List list=session createQuery(hql)

list();

C、優化統計查詢

假設咱們如今有兩張數據庫表,分別是customer表和order表,它們的結構以下:

customerID varchar2(14)

age number(10)

name varchar2(20)

orderID varchar2(14)

order_number number(10)

customer_ID varchar2(14)

如今有兩條HQL查詢語句,分別以下:

from Customer c inner join c orders o group by c age;(1)

select c ID,c name,c age,o ID,o order_number,o customer_ID from Customer c inner join c orders c group by c age;(2)

這兩條語句使用了HQL語句的內鏈接查詢(咱們將在HQL語句的鏈接查詢部分專門討論),如今咱們能夠看出這兩條查詢語句最後所返回的結果是同樣的,可是它們實際上是有明顯區別的,語句(1)檢索的結果會返回Customer與Order持久化對象,並且它們會被置於Hibernate的Session緩存之中,而且Session會負責它們在緩存中的惟一性以及與後臺數據庫數據的同步,只有事務提交後它們纔會從緩存中被清除;而語句(2)返回的是關係數據而並不是是持久化對象,所以它們不會佔用Hibernate的Session緩存,只要在檢索以後應用程序不在訪問它們,它們所佔用的內存就有可能被JVM的垃圾回收器回收,並且Hibernate不會同步對它們的修改。在咱們的系統開發中,尤爲是Mis系統,不可避免的要進行統計查詢的開發,這類功能有兩個特色:第一數據量大;第二通常狀況下都是隻讀操做而不會涉及到對統計數據進行修改,那麼若是採用第一種查詢方式,必然會致使大量持久化對象位於Hibernate的Session緩存中,並且Hibernate的Session緩存還要負責它們與數據庫數據的同步。而若是採用第二種查詢方式,顯然就會提升查詢性能,由於不須要Hibernate的Session緩存的管理開銷,並且只要應用程序不在使用這些數據,它們所佔用的內存空間就會被回收釋放。所以在開發統計查詢系統時,儘可能使用經過select語句寫出須要查詢的屬性的方式來返回關係數據,而避免使用第一種查詢方式返回持久化對象(這種方式是在有修改需求時使用比較適合),這樣能夠提升運行效率而且減小內存消耗。㊣真正的高手並非精通一切,而是精通在合適的場合使用合適的手段。

參數綁定

Hibernate中對動態查詢參數綁定提供了豐富的支持,那麼什麼是查詢參數動態綁定呢?其實若是咱們熟悉傳統JDBC編程的話,咱們就不難理解查詢參數動態綁定,以下代碼傳統JDBC的參數綁定: PrepareStatement pre=connection prepare(「select * from User where user name=?」);

pre setString(1,」zhaoxin」);

ResultSet rs=pre executeQuery();

在Hibernate中也提供了相似這種的查詢參數綁定功能,並且在Hibernate中對這個功能還提供了比傳統JDBC操做豐富的多的特性,在Hibernate中共存在4種參數綁定的方式,下面咱們將分別介紹:

A、 按參數名稱綁定

在HQL語句中定義命名參數要用」:」開頭,形式以下:

Query query=session createQuery(「from User user where user name=:customername and user age=:customerage 」);

query setString(「customername」,name);

query setInteger(「customerage」,age);

上面代碼中用:customername和:customerage分別定義了命名參數customername和customerage,而後用Query接口的setXXX()方法設定名參數值,setXXX()方法包含兩個參數,分別是命名參數名稱和命名參數實際值。

B、 按參數位置綁定

在HQL查詢語句中用」?」來定義參數位置,形式以下:

Query query=session createQuery(「from User user where user name=? and user age =? 」);

query setString(0,name);

query setInteger(1,age);

一樣使用setXXX()方法設定綁定參數,只不過這時setXXX()方法的第一個參數表明邦定參數在HQL語句中出現的位置編號(由0開始編號),第二個參數仍然表明參數實際值。注:在實際開發中,提倡使用按名稱邦定命名參數,由於這不但能夠提供很是好的程序可讀性,並且也提升了程序的易維護性,由於當查詢參數的位置發生改變時,按名稱邦定名參數的方式中是不須要調整程序代碼的。

C、 setParameter()方法

在Hibernate的HQL查詢中能夠經過setParameter()方法邦定任意類型的參數,以下代碼:

String hql=」from User user where user name=:customername 」;

Query query=session createQuery(hql);

query setParameter(「customername」,name,Hibernate STRING);

如上面代碼所示,setParameter()方法包含三個參數,分別是命名參數名稱,命名參數實際值,以及命名參數映射類型。對於某些參數類型setParameter()方法能夠根據參數值的Java類型,猜想出對應的映射類型,所以這時不須要顯示寫出映射類型,像上面的例子,能夠直接這樣寫:query setParameter(「customername」,name);可是對於一些類型就必須寫明映射類型,好比java util Date類型,由於它會對應Hibernate的多種映射類型,好比Hibernate DATE或者Hibernate TIMESTAMP。

D、 setProperties()方法

在Hibernate中可使用setProperties()方法,將命名參數與一個對象的屬性值綁定在一塊兒,以下程序代碼:

Customer customer=new Customer();

customer setName(「pansl」);

customer setAge(80);

Query query=session createQuery(「from Customer c where c name=:name and c age=:age 」);

query setProperties(customer);

setProperties()

方法會自動將customer對象實例的屬性值匹配到命名參數上,可是要求命名參數名稱必需要與實體對象相應的屬性同名。這裏還有一個特殊的setEntity()方法,它會把命名參數與一個持久化對象相關聯,以下面代碼所示:

Customer customer=(Customer)session load(Customer class,」1」);

Query query=session createQuery(「from Order order where order customer=:customer 」);

query setEntity(「customer」,customer);

List list=query list();

上面的代碼會生成相似以下的SQL語句:Select * from order where customer_ID=’1’;E、 使用綁定參數的優點 咱們爲何要使用綁定命名參數?任何一個事物的存在都是有其價值的,具體到綁定參數對於HQL查詢來講,主要有如下兩個主要優點:

①、 能夠利用數據庫實施性能優化,由於對Hibernate來講在底層使用的是PrepareStatement來完成查詢,所以對於語法相同參數不一樣的SQL語句,能夠充分利用預編譯SQL語句緩存,從而提高查詢效率。

②、 能夠防止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=’zhaoxin’ or ‘x’=’x’ and user password=’admin’ 」; 顯然這條HQL語句的where字句將會永遠爲真,而使用戶口令的做用失去意義,這就是SQL Injection***的基本原理。而使用綁定參數方式,就能夠妥善處理這問題,當使用綁定參數時,會獲得下面的HQL語句: from User user where user name=’’zhaoxin’’ or ‘’x=’’x’’ ‘ and user password=’admin’;因而可知使用綁定參數會將用戶名中輸入的單引號解析成字符串(若是想在字符串中包含單引號,應使用重複單引號形式),因此參數綁定可以有效防止SQL Injection安全漏洞。


備註:轉自http://baike.baidu.com/link?url=Y-Qeilq7fjkITBg0PueU0it5A2fxj-asG6L11XjN6fa_T5BaWucYVYSGrZ7olEPFYg1wK2VgHymrHSif48HQvK

相關文章
相關標籤/搜索