Hibernate讀書筆記—–HQL查詢 – JAVA編程語言程序開發技術文章

 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等方法返回查詢結果。
         實例:
[java]
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中最簡單的查詢語句的形式如下:     
[sql]
from Person 
         From關鍵字後面緊跟持久化類的類名。
         大多數情況下, 你需要指定一個別名, 原因是你可能需要在查詢語句的其它部分引用到Person
[sql]
From Person as p 
         子句中可以同時出現多個類, 其查詢結果是產生一個笛卡兒積或產生跨表的連接 
[sql]
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條件
[sql]
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關鍵字後的持久化對象組成的數組。
[sql]
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:
[sql] 
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後持久化類包含的屬性。
[sql] 
Select p.name from Person as p 
         select查詢語句可以返回值為任何類型的屬性,包括返回類型為某種組件(Component)的屬性:
[sql] 
Select p.myEvent.title from Person as p 
         select查詢語句可以返回多個對象和(或)屬性,存放在 Object[]隊列中:
[sql] 
Select p,e from Person as p inner join p.myEvent as e with p.id=e.id 
         Select查詢語句也支持將選擇出的屬性存放到一個List對象中
[sql] 
Select new List(p.name,p.age) from Person as p 
         Select查詢語句還可以將選擇出的屬性直接封裝成一個對象。
[sql] 
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必須有如下構造器:
[java]
ClassTest(int id,String name,int age) 
         Select還支持給選定的表達式名別名:
[html]
Select p.name as personname from Person as p 
         種做法在與子句select new map一起使用時最有用:
[sql]
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後跟持久化類名,不僅會查出該持久化類的全部實例還好查詢出該類的全部子類的全部實例。
[sql] 
from Person as p 
         該查詢語句不僅會查詢出Person的全部實例,還會查詢出Person的子類:Teacher的全部屬性。
         Hibernate 可以在from子句中指定任何 Java 類或接口. 查詢會返回繼承瞭該類的所有持久化子類 的實例或返回聲明瞭該接口的所有持久化類的實例。下面的查詢語句返回所有的被持久化的對象:
[html] 
From java.lang.Object o 

 
         七、Where子句
         where子句允許你將返回的實例列表的范圍縮小. 如果沒有指定別名,你可以使用屬性名來直接引用屬性:
[html]
From Person  where age < 40  
         如果指派瞭別名,需要使用完整的屬性名:
[sql] 
From Person as p where p.age<40 
         復合屬性表達式增強瞭where子句的功能:
[html]
From person p where p.myEvent.title like "%你是" 
         該查詢語句被翻譯為一個含有內連接的SQL查詢語句。
         隻要沒有出現集合屬性,HQL語句可使用點號來隱式連接多個數據表:
[html]
From person p where p.myEvent.event.name like "%hhh"; 
         上的語句SQL需要連接三張表。
         =運算符不僅可以被用來比較屬性的值,也可以用來比較實例:
[html] 
from Cat cat, Cat rival where cat.mate = rival.mate 
[sql] view plaincopyprint?
from Cat cat, Cat rival where cat.mate = rival.mate 
         特殊屬性(小寫)id可以用來表示一個對象的唯一的標識符
[html]
From Person p where p.id=1 
 
From Person p where p.myEvent.id=1 
         第二個查詢是有效的。此時不需要進行表連接,而完全使用面向對象的方式查詢!
         在進行多態持久化的情況下,class關鍵字用來存取一個實例的鑒別之。嵌入where自己中的java類名將會被作為該類的鑒別值。
[sql] 
from Person as p where p.class = Teacher 
         在執行多態的時候,默認會選出Person及其所有子類的實例,但是上面的HQL語句,將隻會選出Teacher類的實例。
         當where子句的運算符隻支持基本類型或者字符串時,where子句中的屬性表達式必須以基本類型或者字符串結尾,不要使用組件類型屬性結尾。
 
         八、order by 子句
         查詢返回的列表(list)可以按照一個返回的類或組件(components)中的任何屬性(property)進行排序:
[sql] 
From Person as p ordery by p.id 
         可選的asc或desc關鍵字指明瞭按照升序或降序進行排序.
 
         九、group by子句
         一個返回聚集值(aggregate values)的查詢可以按照一個返回的類或組件(components)中的任何屬性(property)進行分組:
[sql]
Select p.id,p.name from Person p group by p.age 
         可以使用having子句對分組進行過濾
[html] 
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聚集函數的圓括號)。 甚至相互關聯的子查詢(引用到外部查詢中的別名的子查詢)也是允許的。
[html] 
From Person p where p.age > (select avg(p1.age) from Person p1 ) 
         與SQL子查詢相同,如果子查詢是多行結果集,則應該使用多行運算符。同時HQL子查詢隻可以在select子句或者where子句中出現。
         如果在select子查詢或的列表中包含多項,則在HQL中需要使用一個元組構造符:
[sql]
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屬性,該屬性指定該命名查詢的名字。
[html]
<query name="namedQuery"> 
    <!– 此處確定命名查詢的HQL語句 –> 
    from Person as p 
</query> 

         Session提供一個getNamedQuery(String name)方法用於獲取指定命名HQL查詢並且創建Query對象。
[html] 
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(); 

作者:chenssy

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。