Hibernate提供了強大的查詢系統,使用Hibernate有多種查詢方法可以選擇:可以使用Hibernate的HQL查詢,也可以使用條件查詢,甚至可以使用原生的SQL查詢語句。其中HQL查詢時Hibernate配置的功能強大的查詢語句。HQL是非常有意識的被設計為完全面向對象的查詢,它可以了解如繼承、多态 和關聯之類的概念。
一、HQL查詢
HQL的文法和SQL很相似,但是HQL是一種面向對象的查詢語句,它的操作對象是類、執行個體、屬性等,而SQL的操作對象 是資料表、列等資料庫對象。
由于HQL是完全面向對象的查詢語句,是以可以支援繼承、多态等特性。
HQL查詢依賴于Query類,每一個Query執行個體對應一個查詢對象,它的執行是通過Session的createQuery()方法來獲得的。
執行HQL查詢的步驟:
1、獲得Hibernate Session對象
2、編寫HQL語句
3、調用Session的createQuery方法建立查詢對象
4、如果HQL語句包含參數,則調用Query的setXxx方法為參數指派
5、調用Query對象的list等方法傳回查詢結果。
執行個體:
private void query(){
Session session = HibernateUtil.getSession();
Transaction tx = session.beginTransaction();
//以HQL語句建立Query對象,執行setString方法為HQL語句的參數指派
//Query調用list方法通路查詢的全部執行個體
List list = session.createQuery("select distinct p from Person p where p.name=:name")
.setString("name", "chenssy").list();
//周遊查詢結果
for (Iterator iterator = list.iterator();iterator.hasNext();) {
Person p = (Person) iterator.next();
System.out.println("id="+p.getId()+",age="+p.getAge());
}
session.close();
}
上面的程式先編寫HQL語句後,使用Session的createQuery(hql)方法建立一個Query,Query對象使用setXxx方法為HQL語句的參數指派,最後調用list()方法傳回查詢的全部結果。
在這裡Query對象可以連續多次調用setXxx方法為HQL參數指派。這是因為Hibernate Query的setXxx方法的傳回值為Query本身,是以程式建立Query後,可以直接多次調用setXxx方法為HQL語句的參數指派。
Query對象還包含如下兩個方法:
setFirstResult(int firstResult):設定傳回的結果集從第幾條記錄開始
setMaxResult(int maxResult):設定本次查詢傳回的結果數目
這兩個方法用于對HQL查詢實作分頁控制
二、HQL查詢的from子句
Hibernate中最簡單的查詢語句的形式如下:
from Person
From關鍵字後面緊跟持久化類的類名。
大多數情況下, 你需要指定一個别名, 原因是你可能需要在查詢語句的其它部分引用到Person
From Person as p
子句中可以同時出現多個類, 其查詢結果是産生一個笛卡兒積或産生跨表的連接配接
From Person as p ,MyEvent as e
三、關聯與連接配接
當程式需要從多個資料表中擷取資料時,Hibernate使用關聯映射來處理底層資料表之間的連接配接,一旦我們提供了正确的關聯映射後,當程式通過Hibernate進行持久化通路時,将可利用Hibernate的關聯來進行連接配接。
HQL支援兩種關聯join的形式:implicit(隐式) 與explicit(顯式)。
顯式form子句中明确給出了join關鍵字,而隐式使用英文點号(.)來連接配接關聯實體。
受支援的連接配接類型是從ANSI SQL中借鑒來的。
inner join(内連接配接)
left outer join(左外連接配接)
right outer join(右外連接配接)
full join (全連接配接,并不常用)
使用顯式連接配接,可以通過with關鍵字來提供額外的join條件
From Person as p inner join p.myEvent e with p.id=e.id
從上面可以看出with關鍵字的作用等同于SQL中on關鍵字的作用:用于指定連接配接條件。還有,一個"fetch"連接配接允許僅僅使用一個選擇語句就将相關聯的對象或一組值的集合随着他們的父對象的初始化而被初始化,這種方法在使用到集合的情況下尤其有用,對于關聯和集合來說,它有效的代替了映射檔案中的外聯接與延遲聲明(lazy declarations)。
對于隐式連接配接和顯示連接配接有如下兩個差別:
1、顯式連接配接底層将轉換成SQL99的交叉連接配接,顯式連接配接底層将轉換成SQL99的inner join、left join、right join等連接配接。
2、隐式連接配接和顯式連接配接查詢後傳回的結果不同。使用隐式連接配接查詢傳回的結果是多個被查詢實體組成的集合。使用顯式連接配接的結果分為兩種:如果HQL語句中省略select關鍵字時,傳回的結果也是集合,但集合元素是被查詢持久化對象、所有被關聯的持久化對象所組成的數組。如果沒有省略select關鍵字,傳回的結果同樣是集合,集合中的元素是跟在select關鍵字後的持久化對象組成的數組。
Form Person as p inner join p.myEvent as e with p.id=e.id //...........1
Select p from Person as p inner join p.myEvent as e with p.id=e.id //.........2
........1中傳回的結構是有Person實體和MyEvent實體組成的數組集合。而.........2 傳回的結果是隻有Person組成的集合。
對于有集合屬性的。Hibernate預設采用延遲加載政策。如對于持久化類Person,有集合屬性myEvent。加載Person執行個體時,預設是不加載myEvent的,如果session被關閉了,Person執行個體将會無法通路到關聯的myEvent屬性的。為了解決這個問題,可以再Hibernate映射檔案中配置指定:lazy="false"來關閉延遲加載。或者使用join fetch:
From Person as p join fetch p.myEvent
一個fetch連接配接通常不需要被指定别名, 因為相關聯的對象不應當被用在 where 子句 (或其它任何子句)中。同時,相關聯的對象并不在查詢的結果中直接傳回,但可以通過他們的父對象來通路到他們。
使用fetch關鍵字時需要注意以下幾個問題:
1、fetch不應該與setMaxResults()和setFirstResults()共用,
2、fetch不能與獨立的with條件一起使用
3、如果在一次查詢中fetch多個集合,可以查詢傳回的笛卡爾積
4、full join fetch和right join fetch沒有任何意義
5、對于bag映射而言,同時join fetch多個結合時可能會出現非預期結果
四、select子句
Select子句用于選擇将哪些對象與屬性傳回到查詢結果集中。當然select選擇的屬性必須是from後持久化類包含的屬性。
Select p.name from Person as p
select查詢語句可以傳回值為任何類型的屬性,包括傳回類型為某種元件(Component)的屬性:
Select p.myEvent.title from Person as p
select查詢語句可以傳回多個對象和(或)屬性,存放在 Object[]隊列中:
Select p,e from Person as p inner join p.myEvent as e with p.id=e.id
Select查詢語句也支援将選擇出的屬性存放到一個List對象中
Select new List(p.name,p.age) from Person as p
Select查詢語句還可以将選擇出的屬性直接封裝成一個對象。
Select new ClassTest(p.id,p.name,p.age) from Person as p
但前提是ClassTest支援p.id,p.name,p.age的構造前,假如p.id的資料類型是int,p.name的資料類型是String,p.age的資料類型是int,那麼ClassTest必須有如下構造器:
ClassTest(int id,String name,int age)
Select還支援給標明的表達式名别名:
Select p.name as personname from Person as p
種做法在與子句select new map一起使用時最有用:
Select new map(p.name as personname) from Person as p
五、聚集函數
受支援的聚集函數如下:
avg(...), sum(...), min(...), max(...)
count(*)
count(...), count(distinct ...), count(all...)
Select子句也支援使用distinct和all關鍵字,此時的效果與SQL中的效果相同。
六、多态查詢
Hibernate可以了解多态查詢,from後跟持久化類名,不僅會查出該持久化類的全部執行個體還好查詢出該類的全部子類的全部執行個體。
from Person as p
該查詢語句不僅會查詢出Person的全部執行個體,還會查詢出Person的子類:Teacher的全部屬性。
Hibernate 可以在from子句中指定任何 Java 類或接口. 查詢會傳回繼承了該類的所有持久化子類 的執行個體或傳回聲明了該接口的所有持久化類的執行個體。下面的查詢語句傳回所有的被持久化的對象:
From java.lang.Object o
七、Where子句
where子句允許你将傳回的執行個體清單的範圍縮小. 如果沒有指定别名,你可以使用屬性名來直接引用屬性:
From Person where age < 40
如果指派了别名,需要使用完整的屬性名:
From Person as p where p.age<40
複合屬性表達式增強了where子句的功能:
From person p where p.myEvent.title like "%你是"
該查詢語句被翻譯為一個含有内連接配接的SQL查詢語句。
隻要沒有出現集合屬性,HQL語句可使用點号來隐式連接配接多個資料表:
From person p where p.myEvent.event.name like "%hhh";
上的語句SQL需要連接配接三張表。
=運算符不僅可以被用來比較屬性的值,也可以用來比較執行個體:
from Cat cat, Cat rival where cat.mate = rival.mate
from Cat cat, Cat rival where cat.mate = rival.mate
特殊屬性(小寫)id可以用來表示一個對象的唯一的辨別符
From Person p where p.id=1
From Person p where p.myEvent.id=1
第二個查詢是有效的。此時不需要進行表連接配接,而完全使用面向對象的方式查詢!
在進行多态持久化的情況下,class關鍵字用來存取一個執行個體的鑒别之。嵌入where自己中的java類名将會被作為該類的鑒别值。
from Person as p where p.class = Teacher
在執行多态的時候,預設會選出Person及其所有子類的執行個體,但是上面的HQL語句,将隻會選出Teacher類的執行個體。
當where子句的運算符隻支援基本類型或者字元串時,where子句中的屬性表達式必須以基本類型或者字元串結尾,不要使用元件類型屬性結尾。
八、order by 子句
查詢傳回的清單(list)可以按照一個傳回的類或元件(components)中的任何屬性(property)進行排序:
From Person as p ordery by p.id
可選的asc或desc關鍵字指明了按照升序或降序進行排序.
九、group by子句
一個傳回聚集值(aggregate values)的查詢可以按照一個傳回的類或元件(components)中的任何屬性(property)進行分組:
Select p.id,p.name from Person p group by p.age
可以使用having子句對分組進行過濾
Select p.id,p.name from Person p group by p.age having p.age between 10 and 40
注意:group by子句與 order by子句中都不能包含算術表達式。也要注意Hibernate目前不會擴充group的實體,是以你不能寫group by cat,除非cat的所有屬性都不是聚集的。你必須明确的列出所有的非聚集屬性。
十、子查詢
對于支援子查詢的資料庫,Hibernate支援在查詢中使用子查詢。一個子查詢必須被圓括号包圍起來(經常是SQL聚集函數的圓括号)。 甚至互相關聯的子查詢(引用到外部查詢中的别名的子查詢)也是允許的。
From Person p where p.age > (select avg(p1.age) from Person p1 )
與SQL子查詢相同,如果子查詢是多行結果集,則應該使用多行運算符。同時HQL子查詢隻可以在select子句或者where子句中出現。
如果在select子查詢或的清單中包含多項,則在HQL中需要使用一個元組構造符:
From Person as p where (p.name,p.age) in (select s.name,s,age from Student as s)
十一、命名查詢
HQL查詢還支援将查詢所用的HQL語句放在配置檔案中,而不是程式代碼中。通過這種方式,可以大大提高程式的解耦。
在Hibernate映射檔案中使用<query.../>元素來定義命名查詢。使用<query.../>元素是需要指定一個name屬性,該屬性指定該命名查詢的名字。
<query name="namedQuery">
<!-- 此處确定命名查詢的HQL語句 -->
from Person as p
</query>
Session提供一個getNamedQuery(String name)方法用于擷取指定命名HQL查詢并且建立Query對象。
public void namedQuery(){
Session session = HibernateUtil.getSession();
Transaction tx = session.beginTransaction();
//執行命名查詢
List list = session.getNamedQuery("namedQuery").list();
for (Iterator iterator = list.iterator();iterator.hasNext();) {
Person p = (Person) iterator.next();
System.out.println(p.getName());
}
tx.commit();
session.close();
}
讀李剛:《輕量級JavaEE企業應用實戰》