自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Hibernate Query Language查詢

開發(fā) 后端
本文是對Hibernate Query Language查詢的介紹,分為實體查詢、實體的更新和刪除、屬性查詢、分組與排序、參數(shù)綁定五個部分。

Hibernate Query Language查詢:

Criteria查詢對查詢條件進行了面向?qū)ο蠓庋b,符合編程人員的思維方式,不過HQL(Hibernate Query Language)查詢提供了更加豐富的和靈活的查詢特性,因此Hibernate將HQL查詢方式立為官方推薦的標(biāo)準(zhǔn)查詢方式,HQL查詢在涵蓋Criteria查詢的所有功能的前提下,提供了類似標(biāo)準(zhǔn)SQL語句的查詢方式,同時也提供了更加面向?qū)ο蟮姆庋b。完整的HQL語句形勢如下:
  

  1. Select/update/delete…… from …… where …… group by …… having …… order by …… asc/desc 

其中的update/delete為Hibernate3中所新添加的功能,可見HQL查詢非常類似于標(biāo)準(zhǔn)Hibernate Query Language查詢。由于HQL查詢在整個Hibernate實體操作體系中的核心地位,這一節(jié)我將專門圍繞HQL操作的具體技術(shù)細節(jié)進行講解。

1、 實體查詢:

有關(guān)實體查詢技術(shù),其實我們在先前已經(jīng)有多次涉及,比如下面的例子:

  1.   String hql=”from User user ”;  
  2.   List list=session.CreateQuery(hql).list(); 

上面的代碼執(zhí)行結(jié)果是,查詢出User實體對象所對應(yīng)的所有數(shù)據(jù),而且將數(shù)據(jù)封裝成User實體對象,并且放入List中返回。這里需要注意的是,Hibernate的實體查詢存在著對繼承關(guān)系的判定,比如我們前面討論映射實體繼承關(guān)系中的Employee實體對象,它有兩個子類分別是HourlyEmployee,SalariedEmployee,如果有這樣的HQL語句:“from Employee”,當(dāng)執(zhí)行檢索時Hibernate會檢索出所有Employee類型實體對象所對應(yīng)的數(shù)據(jù)(包括它的子類HourlyEmployee,SalariedEmployee對應(yīng)的數(shù)據(jù))。

因為Hibernate Query Language語句與標(biāo)準(zhǔn)SQL語句相似,所以我們也可以在HQL語句中使用where字句,并且可以在where字句中使用各種表達式,比較操作符以及使用“and”,”or”連接不同的查詢條件的組合??聪旅娴囊恍┖唵蔚睦樱?BR>

  1.   from User user where user.age=20;  
  2.   from User user where user.age between 20 and 30;  
  3.   from User user where user.age in(20,30);  
  4.   from User user where user.name is null;  
  5.   from User user where user.name like ‘%zx%’;  
  6.   from User user where (user.age%2)=1;  
  7.   from User user where user.age=20 and user.name like ‘%zx%’; 

2、 實體的更新和刪除:

在繼續(xù)講解Hibernate Query Language其他更為強大的查詢功能前,我們先來講解以下利用HQL進行實體更新和刪除的技術(shù)。這項技術(shù)功能是Hibernate3的新加入的功能,在Hibernate2中是不具備的。比如在Hibernate2中,如果我們想將數(shù)據(jù)庫中所有18歲的用戶的年齡全部改為20歲,那么我們要首先將年齡在18歲的用戶檢索出來,然后將他們的年齡修改為20歲,最后調(diào)用Session.update()語句進行更新。在Hibernate3中對這個問題提供了更加靈活和更具效率的解決辦法,如下面的代碼:

  1.   Transaction trans=session.beginTransaction();  
  2.   String hql=”update User user set user.age=20 where user.age=18”;  
  3.   Query queryupdate=session.createQuery(hql);  
  4.   int ret=queryupdate.executeUpdate();  
  5.   trans.commit(); 

通過這種方式我們可以在Hibernate3中,一次性完成批量數(shù)據(jù)的更新,對性能的提高是相當(dāng)?shù)目捎^。同樣也可以通過類似的方式來完成delete操作,如下面的代碼:

  1.   Transaction trans=session.beginTransaction();  
  2.   String hql=”delete from User user where user.age=18”;  
  3.   Query queryupdate=session.createQuery(hql);  
  4.   int ret=queryupdate.executeUpdate();  
  5.   trans.commit(); 

如果你是逐個章節(jié)閱讀的化,那么你一定會記起我在第二部分中有關(guān)批量數(shù)據(jù)操作的相關(guān)論述中,討論過這種操作方式,這種操作方式在Hibernate3中稱為bulk delete/update,這種方式能夠在很大程度上提高操作的靈活性和運行效率,但是采用這種方式極有可能引起緩存同步上的問題(請參考相關(guān)論述)。

3、 屬性查詢:

很多時候我們在檢索數(shù)據(jù)時,并不需要獲得實體對象所對應(yīng)的全部數(shù)據(jù),而只需要檢索實體對象的部分屬性所對應(yīng)的數(shù)據(jù)。這時候就可以利用HQL屬性查詢技術(shù),如下面程序示例:

  1.   List list=session.createQuery(“select user.name from User user ”).list();  
  2.   for(int i=0;i<list.size();i++){  
  3.   System.out.println(list.get(i));  
  4.   } 

我們只檢索了User實體的name屬性對應(yīng)的數(shù)據(jù),此時返回的包含結(jié)果集的list中每個條目都是String類型的name屬性對應(yīng)的數(shù)據(jù)。我們也可以一次檢索多個屬性,如下面程序:

  1.   List list=session.createQuery(“select user.name,user.age from User user ”).list();  
  2.   for(int i=0;i<list.size();i++){  
  3.   Object[] obj=(Object[])list.get(i);  
  4.   System.out.println(obj[0]);  
  5.   System.out.println(obj[1]);  
  6.   } 

此時返回的結(jié)果集list中,所包含的每個條目都是一個Object[]類型,其中包含對應(yīng)的屬性數(shù)據(jù)值。作為當(dāng)今我們這一代深受面向?qū)ο笏枷胗绊懙拈_發(fā)人員,可能會覺得上面返回Object[]不夠符合面向?qū)ο箫L(fēng)格,這時我們可以利用HQL提供的動態(tài)構(gòu)造實例的功能對這些平面數(shù)據(jù)進行封裝,如下面的程序代碼:

  1.   List list=session.createQuery(“select new User(user.name,user.age) from User user ”).list();  
  2.   for(int i=0;i  
  3.   User user=(User)list.get(i);  
  4.   System.out.println(user.getName());  
  5.   System.out.println(user.getAge());  
  6.   } 

這里我們通過動態(tài)構(gòu)造實例對象,對返回結(jié)果進行了封裝,使我們的程序更加符合面向?qū)ο箫L(fēng)格,但是這里有一個問題必須注意,那就是這時所返回的User對象,僅僅只是一個普通的Java對象而以,除了查詢結(jié)果值之外,其它的屬性值都為null(包括主鍵值id),也就是說不能通過Session對象對此對象執(zhí)行持久化的更新操作。如下面的代碼:

  1.   List list=session.createQuery(“select new User(user.name,user.age) from User user ”).list();  
  2.   for(int i=0;i  
  3.   User user=(User)list.get(i);  
  4.   user.setName(“gam”);  
  5.   session.saveOrUpdate(user);// 

這里將會實際執(zhí)行一個save操作,而不會執(zhí)行update操作,因為這個User對象的id屬性為null,Hibernate會把它作為一個自由對象(請參考持久化對象狀態(tài)部分的論述),因此會對它執(zhí)行save操作。
  }

4、 分組與排序

A、Order by子句:

與SQL語句相似,HQL查詢也可以通過order by子句對查詢結(jié)果集進行排序,并且可以通過asc或者desc關(guān)鍵字指定排序方式,如下面的代碼:

  1.   from User user order by user.name asc,user.age desc; 

上面HQL查詢語句,會以name屬性進行升序排序,以age屬性進行降序排序,而且與SQL語句一樣,默認(rèn)的排序方式為asc,即升序排序。

B、Group by子句與統(tǒng)計查詢:

在HQL語句中同樣支持使用group by子句分組查詢,還支持group by子句結(jié)合聚集函數(shù)的分組統(tǒng)計查詢,大部分標(biāo)準(zhǔn)的SQL聚集函數(shù)都可以在HQL語句中使用,比如:count(),sum(),max(),min(),avg()等。如下面的程序代碼:

  1.   String hql=”select count(user),user.age from User user group by user.age having count(user)>10 ”;  
  2.   List list=session.createQuery(hql).list(); 

C、優(yōu)化統(tǒng)計查詢:

假設(shè)我們現(xiàn)在有兩張數(shù)據(jù)庫表,分別是customer表和order表,它們的結(jié)構(gòu)如下:

  1.   customer  
  2.   ID varchar2(14)  
  3.   age number(10)  
  4.   name varchar2(20)  
  5.   order  
  6.   ID varchar2(14)  
  7.   order_number number(10)  
  8.   customer_ID varchar2(14) 

現(xiàn)在有兩條HQL查詢語句,分別如下:

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

這兩條語句使用了HQL語句的內(nèi)連接查詢(我們將在HQL語句的連接查詢部分專門討論),現(xiàn)在我們可以看出這兩條查詢語句最后所返回的結(jié)果是一樣的,但是它們其實是有明顯區(qū)別的,語句(1)檢索的結(jié)果會返回Customer與Order持久化對象,而且它們會被置于Hibernate的Session緩存之中,并且Session會負(fù)責(zé)它們在緩存中的唯一性以及與后臺數(shù)據(jù)庫數(shù)據(jù)的同步,只有事務(wù)提交后它們才會從緩存中被清除;而語句(2)返回的是關(guān)系數(shù)據(jù)而并非是持久化對象,因此它們不會占用Hibernate的Session緩存,只要在檢索之后應(yīng)用程序不在訪問它們,它們所占用的內(nèi)存就有可能被JVM的垃圾回收器回收,而且Hibernate不會同步對它們的修改。

在我們的系統(tǒng)開發(fā)中,尤其是Mis系統(tǒng),不可避免的要進行統(tǒng)計查詢的開發(fā),這類功能有兩個特點:第一數(shù)據(jù)量大;第二一般情況下都是只讀操作而不會涉及到對統(tǒng)計數(shù)據(jù)進行修改,那么如果采用第一種查詢方式,必然會導(dǎo)致大量持久化對象位于Hibernate的Session緩存中,而且Hibernate的Session緩存還要負(fù)責(zé)它們與數(shù)據(jù)庫數(shù)據(jù)的同步。而如果采用第二種查詢方式,顯然就會提高查詢性能,因為不需要Hibernate的Session緩存的管理開銷,而且只要應(yīng)用程序不在使用這些數(shù)據(jù),它們所占用的內(nèi)存空間就會被回收釋放。

因此在開發(fā)統(tǒng)計查詢系統(tǒng)時,盡量使用通過select語句寫出需要查詢的屬性的方式來返回關(guān)系數(shù)據(jù),而避免使用第一種查詢方式返回持久化對象(這種方式是在有修改需求時使用比較適合),這樣可以提高運行效率并且減少內(nèi)存消耗。真正的高手并不是精通一切,而是精通在合適的場合使用合適的手段。

5、 參數(shù)綁定:

Hibernate中對動態(tài)查詢參數(shù)綁定提供了豐富的支持,那么什么是查詢參數(shù)動態(tài)綁定呢?其實如果我們熟悉傳統(tǒng)JDBC編程的話,我們就不難理解查詢參數(shù)動態(tài)綁定,如下代碼傳統(tǒng)JDBC的參數(shù)綁定:

  1.   PrepareStatement pre=connection.prepare(“select * from User where user.name=?”);  
  2.   pre.setString(1,”zhaoxin”);  
  3.   ResultSet rs=pre.executeQuery(); 

在Hibernate中也提供了類似這種的查詢參數(shù)綁定功能,而且在Hibernate中對這個功能還提供了比傳統(tǒng)JDBC操作豐富的多的特性,在Hibernate中共存在4種參數(shù)綁定的方式,下面我們將分別介紹:

A、 按參數(shù)名稱綁定:

在HQL語句中定義命名參數(shù)要用”:”開頭,形式如下:

  1.   Query query=session.createQuery(“from User user where user.name=:customername and user:customerage=:age ”);  
  2.   query.setString(“customername”,name);  
  3.   query.setInteger(“customerage”,age); 

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

B、 按參數(shù)位置邦定:

在HQL查詢語句中用”?”來定義參數(shù)位置,形式如下:

  1.   Query query=session.createQuery(“from User user where user.name=? and user.age =? ”);  
  2.   query.setString(0,name);  
  3.   query.setInteger(1,age); 

同樣使用setXXX()方法設(shè)定綁定參數(shù),只不過這時setXXX()方法的第一個參數(shù)代表邦定參數(shù)在HQL語句中出現(xiàn)的位置編號(由0開始編號),第二個參數(shù)仍然代表參數(shù)實際值。

注:在實際開發(fā)中,提倡使用按名稱邦定命名參數(shù),因為這不但可以提供非常好的程序可讀性,而且也提高了程序的易維護性,因為當(dāng)查詢參數(shù)的位置發(fā)生改變時,按名稱邦定名參數(shù)的方式中是不需要調(diào)整程序代碼的。

C、 setParameter()方法:

在Hibernate的HQL查詢中可以通過setParameter()方法邦定任意類型的參數(shù),如下代碼:

  1.   String hql=”from User user where user.name=:customername ”;  
  2.   Query query=session.createQuery(hql);  
  3.   query.setParameter(“customername”,name,Hibernate.STRING); 

如上面代碼所示,setParameter()方法包含三個參數(shù),分別是命名參數(shù)名稱,命名參數(shù)實際值,以及命名參數(shù)映射類型。對于某些參數(shù)類型setParameter()方法可以根據(jù)參數(shù)值的Java類型,猜測出對應(yīng)的映射類型,因此這時不需要顯示寫出映射類型,像上面的例子,可以直接這樣寫:
  query.setParameter(“customername”,name);但是對于一些類型就必須寫明映射類型,比如java.util.Date類型,因為它會對應(yīng)Hibernate的多種映射類型,比如Hibernate.DATA或者Hibernate.TIMESTAMP。

D、 setProperties()方法:

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

  1.   Customer customer=new Customer();  
  2.   customer.setName(“pansl”);  
  3.   customer.setAge(80);  
  4.   Query query=session.createQuery(“from Customer c where c.name=:name and c.age=:age ”);  
  5.   query.setProperties(customer); 

setProperties()方法會自動將customer對象實例的屬性值匹配到命名參數(shù)上,但是要求命名參數(shù)名稱必須要與實體對象相應(yīng)的屬性同名。

這里還有一個特殊的setEntity()方法,它會把命名參數(shù)與一個持久化對象相關(guān)聯(lián),如下面代碼所示:

  1.   Customer customer=(Customer)session.load(Customer.class,”1”);  
  2.   Query query=session.createQuery(“from Order order where order.customer=:customer ”);  
  3.   query. setProperties(“customer”,customer);  
  4.   List list=query.list(); 

上面的代碼會生成類似如下的SQL語句:

  1.   Select * from order where customer_ID=’1’; 

E、 使用綁定參數(shù)的優(yōu)勢:

我們?yōu)槭裁匆褂媒壎麉?shù)?任何一個事物的存在都是有其價值的,具體到綁定參數(shù)對于HQL查詢來說,主要有以下兩個主要優(yōu)勢:

①、 可以利用數(shù)據(jù)庫實施性能優(yōu)化,因為對Hibernate來說在底層使用的是PrepareStatement來完成查詢,因此對于語法相同參數(shù)不同的SQL語句,可以充分利用預(yù)編譯SQL語句緩存,從而提升查詢效率。

②、 可以防止SQL Injection安全漏洞的產(chǎn)生:
  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=’zhaoxin’ or ‘x’=’x’ and user.password=’admin’ ”; 

顯然這條HQL語句的where字句將會永遠為真,而使用戶口令的作用失去意義,這就是SQL Injection攻擊的基本原理。

而使用綁定參數(shù)方式,就可以妥善處理這問題,當(dāng)使用綁定參數(shù)時,會得到下面的HQL語句:

  1.   from User user where user.name=’’zhaoxin’’ or ‘’x=’’x’’ ‘ and user.password=’admin’; 

由此可見使用綁定參數(shù)會將用戶名中輸入的單引號解析成字符串(如果想在字符串中包含單引號,應(yīng)使用重復(fù)單引號形式),所以參數(shù)綁定能夠有效防止SQL Injection安全漏洞。

 

【編輯推薦】

  1. 強人Hibernate文檔筆記(上)
  2. 強人Hibernate文檔筆記(中)
  3. 強人Hibernate文檔筆記(下)
  4. Hibernate一對多關(guān)系的處理
  5. Hibernate的性能優(yōu)化
責(zé)任編輯:仲衡 來源: 百度博客
相關(guān)推薦

2018-08-15 09:55:35

IaaS查詢ZStack

2018-08-14 17:05:11

查詢語言

2009-09-24 18:11:56

Hibernate q

2009-06-29 09:00:42

Hibernate的Q

2009-06-18 12:59:39

Criteria Qu深入淺出Hiberna

2009-09-27 10:19:11

Hibernate命名

2009-09-29 16:29:40

Hibernate查詢

2009-06-17 08:47:00

Hibernate優(yōu)化

2009-09-24 15:27:41

Hibernate查詢

2009-06-18 09:14:08

Hibernate H

2009-06-26 10:01:00

Hibernate的查

2009-09-22 08:39:59

Hibernate F

2009-09-14 14:20:36

LINQ ORM

2009-09-24 10:35:10

Hibernate查詢

2009-06-30 16:44:10

Criteria基本查

2009-06-11 14:40:59

Hibernate分頁Hibernate查詢

2009-06-30 16:46:45

Criteria進階查

2009-09-25 13:39:40

Hibernate屬性

2009-06-18 13:58:06

Hibernate多表Hibernate

2009-09-23 09:16:25

Hibernate復(fù)合
點贊
收藏

51CTO技術(shù)棧公眾號