在這一節(jié)中,我主要介紹下面的內容:
- Session介紹
- Save和Update
- 實體對象的識別
- Hibernate一級緩存
- Hibernate 二級緩存
- Hibernate 事務處理
- 使用復合主鍵
1.1 Session介紹
Session是hibernate運作的中心,對象的生命周期、事務的管理、數(shù)據(jù)庫的存取都與Session息息相關。在Hibernate中使用持久化對象PO(Persistent Object)完成持久化操作,對PO的操作必須在Session的管理下才能同步到數(shù)據(jù)庫。

從這個圖中,我們可以看到流程的第一步就是Configuration對象,Configuration對象的作用就是用于配置和啟動Hibernate。Hibernate應用通過Configuration實例來指定對象/關系映射文件的位置或者動態(tài)配置hibernate的屬性,然后創(chuàng)建一個SessionFactory實例。
注意:Configuration實例是一個啟動期間對象,一旦SessionFactory創(chuàng)建完成它就被丟棄了
第二步,就是創(chuàng)建一個SessionFactory實例,Configuration負責創(chuàng)建SessionFactory實例,是通過Configuration的buildSessionFactory方法創(chuàng)建的,buildSessionFactory方法把Configuration對象所包含的所有配置信息都復制到SessionFactory對象的緩存中當中。同時,SessionFactory對象創(chuàng)建后就不再和Configuration對象關聯(lián)了,即Configuration完成使命,被丟棄了。
一個SessionFactory對象就代表著一個數(shù)據(jù)庫存儲源,通常一個應用程序只需要創(chuàng)建一個SessionFactory實例即可。由此看出其具備如下特點:
- 線程安全:整個應用共用一個SessionFactory實例。
- 重量級: 在SessionFactory中存放了Hibernate配置信息以及映射元素據(jù)信息,這些都需要很大的緩存。
第三步,就是創(chuàng)建Session,Session接口負責執(zhí)行被持久化隊形的CRUD操作(CRUD的任務是完成與數(shù)據(jù)庫的交流,包含了很多常見的SQL語句)。但需要注意的是Session對象是非線程安全的。
Session的生命周期綁定在一個物理的事務上面,Session的主要功能是提供對映射的實體類實例的創(chuàng)建、讀取和刪除操作。實例可能以下面三種狀態(tài)存在:
1.自由狀態(tài):不曾進行持久化,未與任何Session相關聯(lián)。
2.持久化狀態(tài):僅與一個Session相關聯(lián)。
3.游離狀態(tài):已經(jīng)進行過持久化了,但當前未與任何Session相關聯(lián)。
當然,這幾種形態(tài)中也能進行相互之間的轉換:游離狀態(tài)的實例可以通過調用save()、 epersist()或者saveOrUpdate()方法進行持久化。持久化實例可以通過調用delete()變成游離狀態(tài)。通過get()或load()方法得到的實例都是持久化狀態(tài)的。游離狀態(tài)的實例可以通過調用update()、saveOrUpdate()、lock()或者replicate()進行持久化。游離或者自由狀態(tài)下的實例可以通過調用merge()方法成為一個新的持久化實例。
三種實例之間的轉換
1.2 Save還是Update
在我們使用Hibernate的時候可能會有一些疑問?對象的三種狀態(tài)的變化,Hibernate根據(jù)什么來判斷對象是否被更改又是根據(jù)什么來進行判斷的呢。。。如果被修改,是應該增加一條新紀錄還是修改某個記錄?
在使用saveorUpdae方法的時候,這需要在對象映射文件的主鍵中定義unsaved-value屬性,如果不顯示定義,則默認為unsaved-value=null
unsaved-value的屬性值可以是下面的幾點:
- null: 主鍵是對象類型,Hibernate判斷操作對象的主鍵是否為null,來判斷操作對象是否已經(jīng)被持久化,如果是,調用save方法,生成insert語句,在數(shù)據(jù)庫中增加一條記錄;如果不是,設置主鍵則直接生成update的SQL語句,發(fā)送update,如果數(shù)據(jù)庫中沒有那條記錄,則拋出異常。
- none:由于不論主鍵屬性為任何值,都不可能為none,因此hibernate總是對被操作對象發(fā)送update。
- any:由于不論主鍵屬性為任何值,都肯定為any,因此Hibernate總是對project對象發(fā)送save,hibernate生成主鍵。
1.3 實體對象的識別
Hibernate將數(shù)據(jù)庫數(shù)據(jù)同Java實體對象關聯(lián)在一起,使開發(fā)者以操作對象的方式實現(xiàn)數(shù)據(jù)庫的訪問。相對于數(shù)據(jù)庫,比較兩個記錄是否相同,一般比較其主鍵值是否相同就可以了,那么Hibernate持久化的實體對象如何進行比較呢?
當我們需要進行實體對象的識別的時候,可以在持久化類對象中增加equals()、hasCode()兩個方法。
public boolean equals(Object o){
if(this == o) return true;
if(id == null || !(o instanceof Medicine)) return false;
final Medicine medicine = (Medicine) o;
return this.id.equals(medicine.getId());
}
public int hasCode(){
return id == null?System.identityHashCode(this):id.hashCode();
}
這就是在進行比較的時候,我們需要在實體類中進行重寫兩個方法。
1.4 Hibernate一級緩存
首先,我們先來說一下緩存的定義。緩存(Cache)是計算機領域非常通用的概念。它介于應用程序和永久性數(shù)據(jù)存儲源(如硬盤上的文件或者數(shù)據(jù)庫)之間,其作用是降低應用程序直接讀寫永久性數(shù)據(jù)存儲源的頻率,從而提高應用的運行性能。緩存中的數(shù)據(jù)是數(shù)據(jù)存儲源中數(shù)據(jù)的副本,應用程序在運行時直接讀寫緩存中的數(shù)據(jù),只有某些特定時刻按照緩存中的數(shù)據(jù)來同步更新數(shù)據(jù)存儲源。
技術要點:
Hibernate的一級緩存是由Session提供的,因此它只存在于Session的生命周期中,當程序調用方法時,Hibernate會把該對象加入到一級緩存中,當Session關閉時,該Session所管理的一級緩存也會立即被清除。
注意:Hibernate的一級緩存是Session所內置的,不能被卸載,也不能進行任何的配置。
1.5 Hibernate二級緩存
二級緩存是SessionFactory級別的全局緩存,這在Hibernate應用中非常有益于提高數(shù)據(jù)庫訪問效率,但是值得注意的是只有用好了二級緩存才有幫助,不然會導致很多問題,例如:死鎖,數(shù)據(jù)同步等
技術要點:
在使用二級緩存之前,還有一些準備工作。在配置Hibernate二級緩存我們使用了EhCache,需要將Hibernate開發(fā)包lib\optional\ehcache目錄中的ehcache-..*.jar包類庫復制到ClassPath或者是項目的lib目錄下。
另外還需要EhCache的配置文件,可以在Hibernate開發(fā)包project\etc路徑下找到,文件名為ehcache.xml,將文件復制到項目路徑下。修改Hibernate配置文件,增加屬性代碼:

這里我們需要注意的是,指定二級緩存應用到的實體對象需要在指定實體類之后。
1.6 Hibernate事務處理
Hibernate是對JDBC的輕量級對象封裝,Hibernate本身是不具備Transaction處理功能的,hibernate的Transaction實際上是底層的JDBC Transaction的封裝,或者是JTA Transaction的封裝。
1.7 使用復合主鍵
本節(jié)將會介紹復合主鍵對于Hibernate又是如何進行處理,一般情況下有兩種方法進行處理。
可以再建立一個主鍵類,把表中會成為主鍵的數(shù)據(jù)進行持久化處理。這樣的話,我們同樣需要在主鍵類中進行重寫equals()、hashCode()方法。
