Java程式設計師從笨鳥到菜鳥之(五十九)細談Hibernate(十)hibernate查詢排序和元件對映
上一篇:
在實際開發過程中,有很多使用者需要時要把查詢出來的結果進行排序顯示,而不是在資料庫裡面那樣順序混亂那樣的顯示,這樣的話我們不得不要對資料進行排序了,hibernate對資料排序提供了很好的支援,hibernate提供了兩種對查詢到得資料結果進行排序:1:資料庫排序,也就是說在資料庫內部就進行完了排序。2.記憶體排序,也就是說在資料庫中把資料載入到記憶體中在進行排序。其實一般我們推薦使用第二種排序方式,因為在資料庫中排序的效能要遠遠高於在記憶體中排序的效能。
一:資料庫排序
資料庫排序主要是使用集合標籤中的order-by屬性,格式主要是為:
我們就以學生和團隊的關係來說一下:首先來看一下實體之間的資料結構關係:
Student.java
public class Student {
private String id;
private String name;
private String description;
private Team team;
.************set、get方法省略
}
Team.java
public class Team {
private String id;
private String teamname;
private Set students;
***********set、get方法省略
}
從實體上我們可以看出,學生和團隊是一個多對一得資料關係,這個我們以前都看過,也寫過,相信大家都有已經很熟悉了。所以在此具體的配置檔案我們也不多寫了,我們主要來看一下配置排序的地方,下面我們看一下配置的詳細程式碼:
<!-- 以名稱降序返回student集合 -->
<set name="students" table="studentOrder" cascade="all" order-by="name desc">
<key column="team_id"></key>
<one-to-many class="Collection.Order.Student"/>
</set>
從上面可以看出,其實配置資料庫排序很簡單,僅僅是在集合標籤上配置一個order-by屬性即可。
下面我們就具體來看一下測試程式碼:
Transaction t=session.beginTransaction();
Team team=(Team)session.createQuery("from Team t where t.teamname='team1'").uniqueResult();
Set result=team.getStudents();
for (Iterator iterator = result.iterator(); iterator.hasNext();) {
Student object = (Student) iterator.next();
System.out.println(object.getName());
}
t.commit();
執行這塊程式碼,我們一起來看一下控制檯的列印結果:
測試結果:
Hibernate: select team0_.id as id1_, team0_.teamname as teamname1_ from teamOrder team0_ where team0_.teamname='team1'
Hibernate: select students0_.team_id as team4_1_, students0_.id as id1_, students0_.id as id0_0_, students0_.name as name0_0_, students0_.description as descript3_0_0_, students0_.team_id as team4_0_0_ from studentOrder students0_ where students0_.team_id=? order by students0_.name desc
hello
default
bug
從上面輸出的sql語句就可以看出,我們查詢到得資料時以student表中的name進行排序的。所以我們資料庫排序的配置就這麼結束了。
二.記憶體排序
記憶體排序,顧名思義,就是在記憶體中排序,把查詢到得結果載入到記憶體以後驚醒排序。Hibernate在配置檔案中也給我提供了記憶體排序的配置,那就是sort屬性,它有兩個屬性值可以直接使用,分別是unsorted(不排序)以及natural(自然排序,即升序),此外,我們還可以自定義排序規則,方式是定義一個類,讓其實現Comparator介面,並且實現該介面中的compare方法,在該方法中實現排序規則即可。然後將該自定義排序規則的類名作為sort的屬性值即可。<set>和<map>元素都具有sort屬性,如果設定了該屬性,就會對記憶體中的集合物件進行排序。
<set>元素的sort屬性為natural,表示對集合中的字串進行自然排序。Hibernate採用org.hibernate.PersistentSortedSet作為Set的實現類,PersistentSortedSet類實現了 java.util.SortedSet介面。當Session儲存一個物件時,會呼叫 org.hibernate.type.SortedSetType類的wrap()方法,把物件的集合屬性包裝為 SortedSet類的例項,下面我們看一下wrap()方法的原始碼如下:
public PersistentCollection wrap
(SessionImplementor session, Object collection) {
return new PersistentSortedSet
( session, (java.util.SortedSet) collection );
}
從wrap()方法的原始碼看出,應用程式中建立的物件的集合屬性必須是java.util.SortedSet型別,否則以上wrap()方法會丟擲ClassCastException。
其實記憶體排序和資料庫排序是一樣的,只是配置的引數不同而已,都是在集合標籤配置一下,所以在此我們就不以示例演示了。
三、元件對映(component)
在hibernate中,component是某個實體物件的邏輯組成部分,它與實體的根本區別是,component是沒有標識的,它是一個邏輯組成部分,完全從屬於某個實體,這樣就在傳統資料庫上,實現了物件的細粒度劃分,層次分明,實現了面向物件的領域劃分
見下圖:
把User和Employee中共同的屬性(各種聯絡方式)拿出來,放在(抽象到)到一個單獨的類中。這樣物理上看有三個類,不過實體類還是隻有User和Employee兩個,也就是說資料庫裡只有User和Employee兩張表。
下面我們就來看一下user和contact的實體及相關配置:
user.java
public class User {
privateint id;
privateString name;
//聯絡方式
privateContact contact;
********************set、get省略
}
contact.java
public class Contact {
privateString address;
privateString contactTel;
privateString email;
privateString zipCode;
********************set、get省略
}
user.hbm.xml
<?xmlversion="1.0"?>
<!DOCTYPEhibernate-mapping PUBLIC
"-//Hibernate/Hibernate MappingDTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<classname="com.bjsxt.hibernate.User" table="t_user">
<idname="id">
<generatorclass="native"/>
</id>
<propertyname="name"/>
<componentname="contact">
<propertyname="address"/>
<propertyname="contactTel"/>
<propertyname="email"/>
<propertyname="zipCode"/>
</component>
</class>
</hibernate-mapping>
從配置上來看,其實這個地方很好理解,user把contact看做是組成的一部分,只是把他抽出一個單獨的實體類了而已,這也正好體現了程式碼的複用性,其實他就是一對一關係的對映。
如果想要生成兩張表,hibernate也提供了相關的配置機制,其實只是換了換標籤而已,把component標籤換成composite-element,僅此而已,這樣就能生成兩張表了。