hibernate--HQL查詢語句(1)

本章介紹了Hibernate的幾種主要檢索方式:HQL檢索方式、QBC檢索方式、SQL檢索方式。HQL是Hibernate Query Language的縮寫,是官方推薦的查詢語言。QBC是Query By Criteria的縮寫,是Hibernate提供的一個查詢接口。Hibernate是一個輕量級的框架,它允許使用原始SQL語句查詢數據庫。

6.1 HQL基礎

HQL是Hiberante官方推薦的Hibernate檢索方式,它使用類似SQL的查詢語言,以面向對象的方式從數據庫中查詢。可以使用HQL查詢具有繼承、多態和關聯關係的數據。在檢索數據時應優先考慮使用HQL方式。

6.1.1 默認數據庫表和數據

在講解本章時,在沒有特殊說明時,用到的數據庫均爲joblog,也就是在第4章建立的數據庫。joblog中添加了3個表:學生表student、課程表course和選課表sc。

學生表student中各字段的結構如圖6-1所示,字段的中文含義在Comment列中。

 

圖6-1 學生表的數據結構

學生表student中的數據如圖6-2所示,沒有特殊說明時,用到的均爲這6條記錄。

此處仍然使用在第4章建立的HibernateProject項目,但是這裏新建了一個包hibernate.ch06,這個包存放本章中的所有代碼。在hibernate.ch06包中建立學生表對應的持久化類Student.java,代碼如下。

 

圖6-2 學生表中的數據

package hibernate.ch06;

//學生類

public class Student {

       private Integer id;             //對象標識符

      private Integer sno;            //學號

      private String sname;          //姓名

      private String ssex;            //性別

      private String sdept;           //所在系別

      private Integer sage;           //年齡

      private String saddress;       //籍貫

     …… //省略了所有的get/set訪問器

}

課程表course中的各個字段的結構如圖6-3所示,字段的中文含義在Comment列中。

 

圖6-3 課程表的結構

課程表中的數據如圖6-4所示,如果沒有特殊說明,用到的均爲這4條記錄。

 

圖6-4 課程表的數據

在hibernate.ch06中新建持久化類Course.java類,代碼如下。

package hibernate.ch06;

//課程類

public class Course {

       private Integer id;             //對象標識符

     private Integer cno;            //課程號

       private String cname;           //課程名

       private Integer Ccredit;       //學分

      

       …… //省略了get/set訪問器

}

選修表sc(sc爲student-course的縮寫)的結構如圖6-5所示,字段的中文含義在Comment列中。

 

圖6-5 選修表的結構

選修表中的數據如圖6-6所示,沒有特殊說明時,用到的均爲這5條記錄。

 

圖6-6 選修表的數據

在hibernate.ch06中新建持久化類SC.java,SC.java的代碼如下。

package hibernate.ch06;

//選課類

public class SC implements java.io.Serializable {

       private Integer id;             //id

       private Integer sno;           //學號

       private Integer cno;           //課程號

       private Integer grade;         //成績

     public SC() {

       }

      …… //省略get/set訪問器

}

後面的章節中將用這3個表和3個持久化類進行講解。

6.1.2 檢索類的所有對象

使用HQL語句可以檢索出一個類的所有對象,如HQL語句“from Student”表示檢索Student類的所有對象。下面的程序檢索學生類的所有對象。

        Query query=session.createQuery("from Student"); //創建Query對象

        List list=query.list();                                                   //執行查詢

       

        //以下代碼做顯示用,以後不再寫出來

        Iterator it=list.iterator();

        while(it.hasNext()){

                Student stu=(Student)it.next();

                System.out.println("id"+stu.getId());

                System.out.println("name"+stu.getSname());

                System.out.println("\n");

        }

    session.createQuery()以HQL查詢語句爲參數,生成一個查詢對象。本例中的HQL語句爲“from Student”,這是from子句,格式如下。

from 類名

其中,類名可以爲類的全限定名,如:

from hibernate.ch06.Student

Hibernate使用自動引入功能(auto import),會自動尋找需要的類,所以不推薦使用類的全限定名。注意,類名區分大小寫,如果寫成from student,將會拋出以下異常。

java.lang.NoClassDefFoundError: hibernate/ch06/student (wrong name: hibernate/ch06/Student)

     HQL關鍵字不區分大小寫,FROM、from和From是一樣的。

調用query.list()時,真正開始執行HQL查詢語句,並把查詢的結果放在List中。

本例中查詢的是Student類中的所有屬性,如果查詢Student類中的某一個或某幾個屬性,如查詢所有學生的姓名和所在系,需要用到屬性查詢。

6.1.3 檢索類的某幾個屬性

與SQL語句類似,HQL語句可以檢索類的某一個或者某幾個屬性。以下代碼查詢所有學生的姓名和所在系。

        //創建Query對象

        Query query=session.createQuery("select Student.sname,Student.sdept from Student");

        List list=query.list();      

//執行查詢

        //以下代碼顯示查詢的信息

        Iterator it=list.iterator();

        while(it.hasNext()){

                Object[] stu=(Object[])it.next();

                System.out.println("id"+stu[0]);

                System.out.println("name"+stu[1]);

                System.out.println("\n");

        }

     屬性查詢使用select關鍵字,屬性查詢的格式如下。

select 屬性1,屬性2,… from 類名

     屬性前可以加上類名加以限定,如:

select 屬性1,屬性2,… from 類名

但一般沒有必要。

屬性查詢區分大小寫,上面的代碼中如果寫成:

select SNAME,Sdept from Student

將拋出異常,提示找不到屬性SNAME和屬性Sdept。

     查詢結果將只顯示查詢的屬性列。

    屬性查詢的結果,對於用it.next()獲得的每條記錄,可以存儲在Object[]數組中,以便進行存取

6.1.4 指定別名

在查詢時,可以用關鍵字as指定查詢的別名,指定別名可以簡化查詢,有時必需指定別名才能進行查詢。以下代碼查詢學號中含有4的學生的姓名和所在系。

select s.sname,s.sdept from Student as s wheres.sno like '%4%'from Student s

s就是類Student的別名。注意as可以省略,即下面的查詢語句和上面的語句是等效的。

select s.sname,s.sdept from Student s where s.sno like '%4%'from Student s

6.1.5 where條件子句

where條件子句跟SQL中的where條件子句類似,它檢索符合條件的對象。例如,查詢所有所在系別爲計算機系的學生:

select s.sname,s.sdept from Student s where s.dept=’計算機’

     where子句指定查詢的條件,其語法和SQL類似

     在where子句中可以指定比較運算符:>、>=、<、<=、<>,其含義分別爲大於、大於等於、小於、小於等於、不等於。

查詢年齡在22到23歲的學生:

from Student s where s.sage>=22 and s.sage<=23

     在where子句中指定查詢的屬性是否爲null:is null、is not null,其含義分別表示爲空和不爲空

查詢所在籍貫爲空的學生:

from Student s where s.saddress is null

6.1.6 使用distinct過濾掉重複值

使用distinct關鍵字將去掉結果中的重複值,只檢索符合條件的對象。如下面的例子檢索學生實例中的不重複的年齡。

        Session session=HibernateSessionFactory.currentSession();            //創建Session

        String hql="select distinct s.sage from Student s";                   //HQL查詢語句

        Query query=session.createQuery(hql);                                    //創建查詢

        List list=query.list();                                                    //執行查詢

檢索的結果如下,可見結果中去掉了一個重複的22歲。

20

21

22

23

24

 

《二》

 

1.實體的更新和刪除:
  在繼續講解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();

 2.分組與排序
  AOrder by子句:
  與SQL語句相似,HQL查詢也可以通過order by子句對查詢結果集進行排序,並且可以通過asc或者desc關鍵字指定排序方式,如下面的代碼:
  from User user order by user.name asc,user.age desc;
  上面HQL查詢語句,會以name屬性進行升序排序,以age屬性進行降序排序,而且與SQL語句一樣,默認的排序方式爲asc,即升序排序。
  BGroup 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表,它們的結構如下:
  customer
  ID varchar2(14)
  age number(10)
  name varchar2(20)
  order
  ID 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檢索的結果會返回CustomerOrder持久化對象,而且它們會被置於HibernateSession緩存之中,並且Session會負責它們在緩存中的唯一性以及與後臺數據庫數據的同步,只有事務提交後它們纔會從緩存中被清除;而語句

   2返回的是關係數據而並非是持久化對象,因此它們不會佔用HibernateSession緩存,只要在檢索之後應用程序不在訪問它們,它們所佔用的內存就有可能被JVM的垃圾回收器回收,而且Hibernate不會同步對它們的修改。
  在我們的系統開發中,尤其是Mis系統,不可避免的要進行統計查詢的開發,這類功能有兩個特點:第一數據量大;第二一般情況下都是隻讀操作而不會涉及到對統計數據進行修改,那麼如果採用第一種查詢方式,必然會導致大量持久化對象位於HibernateSession緩存中,而且HibernateSession緩存還要負責它們與數據庫數據的同步。而如果採用第二種查詢方式,顯然就會提高查詢性能,因爲不需要HibernateSession緩存的管理開銷,而且只要應用程序不在使用這些數據,它們所佔用的內存空間就會被回收釋放。
  因此在開發統計查詢系統時,儘量使用通過select語句寫出需要查詢的屬性的方式來返回關係數據,而避免使用第一種查詢方式返回持久化對象(這種方式是在有修改需求時使用比較適合),這樣可以提高運行效率並且減少內存消耗。㊣真正的高手並不是精通一切,而是精通在合適的場合使用合適的手段。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章