天天看點

SSH:Hibernate架構(Hibernate:HQL與QBC查詢方式詳解 )

首先來看一下,hibernate提供的幾種檢索方式:

1.導航對象圖檢索方式 :根據已經加載的對象,導航到其他對象。例如,對于已經加載的Customer對象,調用它的getOrders().iterator()方法就可以導航到所有關聯的Order對象,假如在關聯級别使用了延遲加載檢索政策,那麼首次執行此方法時,Hibernate會從資料庫中加載關聯的Order對象,否則就從緩存中取得Order對象。

2、OID檢索方式 :按照對象的OID來檢索對象。Session的get()和load()方法提供了這種功能。如果在應用程式中事先知道了OID,就可以使用這種檢索對象的方式。

3、HQL檢索方式 :Hibernate提供了Query接口,它是Hibernate提供的專門的HQL查詢接口,能夠執行各種複雜的HQL查詢語句。

4、QBC檢索方式 :使用QBC(Query By Criteria)API來檢索對象。這種API封裝了基于字元串形式的查詢語句,提供了更加面向對象的接口。

前兩種在前面我們都熟練的用過多次了,現在我們來看一下HQL檢索方式。HQL(Hibernate Query Language)是面向對象的查詢語言,它和SQL查詢語言有些相似。在Hibernate提供的各種檢索方式中,HQL是使用最廣的一種檢索方式。它具有以下功能:

–在查詢語句中設定各種查詢條件

–支援投影查詢,即僅檢索出對象的部分屬性

–支援分頁查詢

–支援連接配接查詢

–支援分組查詢,允許使用having和group by關鍵字

–提供内置聚集函數,如sum()、min()和max()

–支援子查詢,即嵌入式查詢

–支援動态綁定參數

下面我們通過一個執行個體來看一下HQL檢索的步驟:

[java] view plaincopyprint?

//建立一個Query對象

Query query=session.createQuery(“from Customer as c where ”

+” c.name=:customerName ”

+”and c.age=:customerAge”);

//動态綁定參數

query.setString(“customerName”,”Tom”);

query.setInteger(“customerAge”,21);

//執行查詢語句,傳回查詢結果

List result= query.list();

從上面這個執行個體我們可以看出:

(1)通過Session的createQuery()方法建立一個Query對象,它包含一個HQL查詢語句。HQL查詢語句可以包含命名參數,如“customerName”和“customerAge”都是命名參數。

(2)動态綁定參數。Query接口提供了給各種類型的命名參數指派的方法,例如setString()方法用于為字元串類型的customerName命名參數指派。

(3)調用Query的list()方法執行查詢語句。該方法傳回List類型的查詢結果,在List集合中存放了符合查詢條件的持久化對象。

Query中還提供了良好的方法連程式設計方式,檢視hibernate的API我們可以發現,query類提供的set方法的傳回值還是query對象,這樣可以使代碼更為簡介:例如。

[java] view plaincopyprint?

List result=session.createQuery(“……”) .setString(“customerName”,”Tom”)

.setInteger(“customerAge”,21) .list();

QBC

采用HQL檢索方式時,在應用程式中需要定義基于字元串形式的HQL查詢語句。 QBC API 提供了檢索對象的另一種方式,它主要由Criteria接口、Criterion接口和Expression類組成,它支援在運作時動态生成查詢語句。

QBC檢索步驟:

1)調用Session的createCriteria()方法建立一個Criteria對象。

2)設定查詢條件。Expression類提供了一系列用于設定查詢條件的靜态方法,這些靜态方法都傳回Criterion執行個體,每個Criterion執行個體代表一個查詢條件。Criteria的add()方法用于加入查詢條件。

3)調用Criteria的list()方法執行查詢語句。該方法傳回List類型的查詢結果,在List集合中存放了符合查詢條件的持久化對象。下面還是通過一個執行個體來看一下QBC查詢的具體步驟:

[java] view plaincopyprint?

//建立一個Criteria對象

Criteria criteria=session.createCriteria(Customer.class);

//設定查詢條件,然後把查詢條件加入到Criteria中

Criterion criterion1= Expression.like(“name”, “T%”) ;

Criterion criterion2= Expression.eq(“age”, new Integer(21)) ;

criteria=criteria.add(criterion1);

criteria=criteria.add(criterion2);

//執行查詢語句,傳回查詢結果

List result=criteria.list();

對于以上程式代碼,當運作Criteria的list()方法時,Hibernate執行的SQL查詢語句為:

select * from CUSTOMERS where NAME like ‘T%’ and AGE=21;

注:Expression;類是org.hibernate.criterion.Restrictions的子類,是以也可以換成該類。Criteria也是采用的方法連的程式設計風格,因為add方法傳回值也是Criteria,就像下面這段代碼:

[java] view plaincopyprint?

List result=session.createCriteria(Customer.class).add(Expression.like(“name”, “T%”) .add(Expression.eq(“age”, newInteger(21)) .list();

Query和Criteria接口都提供了用于分頁顯示查詢結果的方法:

–setFirstResult(int firstResult):設定從哪一個對象開始檢索,參數firstResult表示這個對象在查詢結果中的索引位置,索引位置的起始值為0。預設情況下,Query和Criteria接口從查詢結果中的第一個對象,也就是索引位置為0的對象開始檢索。

–setMaxResult(int maxResults):設定一次最多檢索出的對象數目。預設情況下,Query和Criteria接口檢索出查詢結果中所有的對象。

分頁查詢:

采用HQL檢索方式 :

[java] view plaincopyprint?

Query query = session.createQuery(“from

Customer c

order by c.name asc”);

query.setFirstResult(0);

query.setMaxResults(10);

List result = query.list();

采用QBC檢索方式

[java] view plaincopyprint?

Criteria criteria = session.createCriteria(

Customer.class);

criteria.addOrder( //criteria裡面提供添加排序方式的方法

Order.asc(“name”) );

criteria.setFirstResult(0);

criteria.setMaxResults(10);

List result = criteria.list()

上面我們大體了解了hql語句和QBC兩種查詢方式,具體的用法我們來看一下,首先看一下HQL.

我們平時查詢的時候,HQL語句總是”from 類名”,這樣查詢,這是我們想要查詢出對應對象的所有屬性。當我們隻是想查詢實體類的其中的幾個字段,而不是整個實體類的對象時,我們就需要把前面省略的hql語句加上了。例如HQL語句:select s.name,s.age from student s ,他代表隻是查詢student表中的name和age屬性,其他的不要。這時調用query。List()方法時傳回的不是一個個對象了,因為我們查詢的隻是對象的一部分屬性。那查詢到的list集合裡是什麼東東呢。其實list對象中裡面每一個元素是一個object對象的數組,每一個數組包含查詢對象的幾個字段。這些資料隻是一些遊離的資料。我們想獲得的字段資料可以用下面方式去周遊。

代碼如下:

以上情況還可以用另一種方式來解決但這種方式方式成功執行的前提是,在student實體類裡面構造了包含name和age兩個屬性的構造方法。

[java] view plaincopyprint?

Query query = session.createQuery(“select new Student(s.name, s.age) from Student s”);

List list = query.list();

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

{Student student = (Student)list.get(i) System.out.println(student.getName() + “, ” + student.getAge());

System.out.println(student.getCardId());//此處傳回空,資料庫沒有查該字段

}

通過上面HQL語句我們可以看出,這時查詢出來的就是一個個student對象了,而不是一個個遊離的資料了,這裡一定要注意HQL語句的寫法。這種寫法在sql語句中肯定是不支援的。
    HQL語句進行内連接配接查詢:from Team t  join t.student;這條内連接配接語句意思為讓team表和student表進行内連接配接查詢。很多同學回想沒有on語句,查詢條件是什麼呢?這是由于hbm檔案已經注明了表之間的字段連接配接關系,是以他會自動去on連接配接。下面看一下自動生成的sql語句大家就沒白了。
           

Hibernate自動生成的查詢語句為:

Hibernate配置給我們提供了一個格式化sql語句的配置,配置sql_format的屬性為true,就會向上面那樣,得到格式化的sql語句。
      在内連接配接查詢結果中,剛開始我有這麼一個疑問,連接配接查詢得到的結果集是兩個表中的并集集合,那得到的對象到底是哪一個呢?不是student。也是不是team。原來,hibernate早就給我們準備了這個東西。當我們調用list方法獲得結果的集合時,得到的集合實際上是object數組的集合。這個數組裡面一般有兩個對象,像上面那條hql語句就是得到的student對象和team對象數組的集合,下面我們就看一下具體的代碼實作:
           

[java] view plaincopyprint?

Query query = session.createQuery(“from Team t join t.students”);

List list = query.list();

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

{

Object[] obj = (Object[]) list.get(i);

Team team = (Team)obj[0];

Student student = (Student)obj[1];

System.out.println(team.getTeamName());

System.out.println(student.getName());

}

内連接配接中還深藏着一個不為人知的秘密,當我們把延遲加載設為true,也就是讓他延遲加載對應對象資訊時,我們在session關閉之後去周遊list集合,這時你會發現一樣的加載出來對應的student的資訊,這時因為内連接配接查詢把配置檔案中的延遲加載資訊給覆寫掉了。在session關閉之前就把對應的對象資訊給加載出來了。
           

hql中實體參數設定

下面我們在來看一下hibernate用hql中實體參數設定,所謂實體參數設定就是在利用HQL語句執行操作時,對HQL語句中設定參數,以前我們接觸到的都是一些基本資料類型的參數設定,hibernate中都提供了相應的set方法,下面我們來看一下下面一個hql查詢:

[java] view plaincopyprint?

Team team=session.get(Team.class,1);

Query query = session.createQuery(“from student s where s.team=:team and s.age>20”);

在這個地方,我們查詢的條件為學生對應的team對象與剛查詢出來的對象相等。在hibernateAPI中提供了兩種方式設定這個地方的參數,下面我們一一來看一下:
           

1.第一種:

query.setParameter(“team”,team,Hibernate.entity(Team.class));這種方式需要三個參數,第一個參數是指定設定的參數,這裡設定的是上面hql語句中的team參數,第二個參數是設定參數的值,第三個參數是一個Type類型的資料,hibernate中提供了一個Hibernate類,他裡面包含了大量的靜态工具方法,其中就有獲得Type對象的方法entity。

2.第二種:

query.setEntity(“team”,team),這個方法比較簡單,并且比較實用,我們在大多數的時候都使用這一個,他和設定基本資料類型的set方法比較相識。直接設定參數名和參數值就OK了。

值得注意的是,這裡的hql語句這樣比較兩個對象是否相等,其實在hibernate底層會轉換成對應的外鍵關聯。

過濾:

hibernateAPI提供了一個起到過濾器作用的方法,這個方法就是createFiter(object collection,string s)方法,他有兩個參數,第一個參數是指所要過濾的對象,也就是集合對象,第二個參數指的是過濾語句,其實就是hql語句的一部分:例如下面這段代碼:

[java] view plaincopyprint?

Query query = session.createFilter(team.getStudents(), “where age > 20”);

List list = query.list();

QBC:作為真正的面向對象對資料庫進行操作的一種方式,其内部提供了大量的API對資料庫操作和條件,下面我們根據具體示例來看一下其API的的用法:

[java] view plaincopyprint?

//增加年齡限制12-30歲

Criteria criteria = session.createCriteria(Student.class).add(

Restrictions.between(“age”, new Integer(12), new Integer(30)));

//增加name條件限制,名字以t開頭的

Criteria criteria = session.createCriteria(Student.class).add(

Restrictions.like(“name”, “t%”));

//增加範圍限制,名字必須是”jerry”, “spark”, “tom”中的一個

String[] names = { “jerry”, “spark”, “tom” };

Criteria criteria = session.createCriteria(Student.class).add(

Restrictions.in(“name”, names));

//對查詢到的資料進行排序,以age升序,以cardid降序

Criteria criteria = session.createCriteria(Student.class).addOrder(

Order.asc(“age”)).addOrder(Order.desc(“cardId”));

//執行資料查詢

List list = criteria.list();