1. 程式人生 > >hibernate框架學習之一級緩存

hibernate框架學習之一級緩存

commit 任務 功能區 出了 運行 發生 快照 class 可以關閉

l緩存是存儲數據的臨時空間,減少從數據庫中查詢數據的次數

lHibernate中提供有兩種緩存機制

?一級緩存(Hibernate自身攜帶)

?二級緩存(使用外部技術)


lHibernate的一級緩存即Hibernate操作數據時所對應的臨時數據存儲區域,這個區域是綁定Session對象的,也就是說每開啟一個Session對象,就會產生對應的一級緩存空間,當Session對象關閉時,該空間內的數據,也就是其中保存的PO對象,會轉化為DO對象。

lHibernate的一級緩存是Session級別的緩存,與Session對象一一對應,不同的Session間無法共享緩存數據。


l驗證Hibernate一級緩存的存在性

lget與load方法的區別

?相同:load與get方法查詢數據,首先查找一級緩存中是否存在待查找數據,如果存在,直接獲取;如果不存在,從數據庫中通過SQL語句獲取數據庫端對應的數據

?不同:load方法查詢到的對象,如果只獲取數據的OID則不進行任何查詢,直接返回OID;如果需要使用OID之外的數據,則按照上述規則查找對應的數據

l通過配置可以關閉延遲加載——lazy屬性


Hibernate延遲加載開啟與關閉

l在映射文件.hbm.xml文件中,可以配置是否使用延遲加載特性,可以將該屬性配置在三個位置

技術分享圖片


Hibernate使用一級緩存

lHibernate的一級緩存可以理解為數據的中轉站

lHibernate進行數據R操作

?如果一級緩存中存在該數據,直接取出使用

?如果一級緩存中不存在,執行SQL語句從數據庫中獲取

lHibernate進行數據CUD操作

?將待操作的數據及操作模式放入一級緩存

?刷新一級緩存,檢測是否需要進行持久化


Hibernate一級緩存刷新方式

lHibernate的一級緩存中保存有本次Session操作過程中的所有數據,這些數據在如下情況提交到數據庫進行同步更新,對需要進行更新的數據執行對應的SQL語句

?執行事務提交

?t.commit();

?刷新Session範圍的緩存數據

?s.flush();

?關閉Session

?s.close();


Hibernate刷新一級緩存——快照

l當任意數據進入Hibernate一級緩存中時,馬上保存該數據的一份克隆(快照),當一級緩存刷新時,對每一個緩存中的對象進行比對,如果快照數據與當前數據相同,無任何操作;如果快照數據與當前數據不同,則將修改後的數據更新到數據庫中,執行對應的SQL語句,並更新快照數據

l一級緩沖中保存的對象全是PO,因此PO可以更新數據庫對應信息,而TO與DO則不具備這樣的能力

l刷新一級緩存

?s.flush();

l清除一級緩存

?s.clear();

l清除一級緩存中指定對象

?s.evict(obj);

l更新一級緩存中指定對象(使用數據庫中數據覆蓋一級緩存數據及快照數據)

?s.refresh(obj);


Hibernate一級緩存刷新時機

l所謂Hibernate一級緩存刷新時機指一級緩存中存在的修改數據何時會被同步到數據庫表中

l常用的刷新時機有四種(FlushModel常量)

?ALWAYS:任意操作導致刷新(效率過低)

?AUTO:根據操作功能區別是否刷新(默認)

?COMMIT:提交事務時刷新

?MANUAL:手動執行刷新時進行刷新(關閉session不會觸發)

l設置方式:

?s.setFlushMode(FlushMode.COMMIT);

?設置在Session對象獲得後


Hibernate一級緩存常用操作註意事項

lsave()

lupdate()

lmerge()

lsaveOrUpdate()

lget()/load()

ldelete()

lsave操作可以將一個TO轉換為PO

l操作步驟:

?將TO裝入Session,TO→PO

?使用ID生成器,為PO分配唯一標識OID

?如果手工給出了OID,生成器會根據配置將此OID進行替換

?在執行計劃中添加INSERT語句,通過映射文件中的配置,將對象中的屬性值添加到INSERT語句中

l註意:

?TO執行了save操作後,TO轉換為PO,此時如果修改PO的OID,那麽會產生錯誤,通知用戶一個PO的OID發生了變化,這是不被允許的


lupdate操作可以將一個DO轉換為PO

l操作步驟:

?為一個TO指定OID,TO→DO

?使用update更新DO,DO→PO

?在執行計劃中添加UPDATE語句,通過映射文件中的配置,將對象中的屬性值添加到UPDATE語句中

l註意:

?DO轉化PO使用update語句完成,如果在轉化完成後對PO進行屬性更新,只會產生一條update語句,此時PO狀態的改變會在緩存進行刷新時才完成最終操作,除非提前刷新緩存

?PO的更新不使用update語句,緩存刷新時自動完成

lUpdate將DO→PO操作會強制完成一次更新操作,無論數據是否發生變化,此時可根據業務需要選擇

?如果用戶數據沒有發生變化,則不執行update語句

?如果用戶數據發生了變化,則執行update語句

l完成上述操作的前提是將update操作對應的數據先與數據庫中的數據進行比對,也就是update操作前執行查詢語句select,可以通過配置完成上述操作

?在class元素中配置select-before-update,該配置值默認false

?技術分享圖片

l註意:此設定開啟後,整體效率會下降,慎重選擇.

lupdate操作將DO轉換為PO後,最終將執行對應的UPDATE語句將數據持久化到數據庫中,此時如果數據庫表中不存在對應OID的數據,程序也將出錯

?該錯誤隸屬於基本的SQL操作,SQL語句更新一個不存在的東西將產生0行數據影響的一個操作,而對於Hibernate將此現象歸屬於執行了一個不可能完成的任務,最終以異常的形式展示給開發者

?例如:A用戶讀取了一條數據,準備修改該數據,此時B用戶將這條數據刪除了,A用戶在修改該數據時,該數據已經消失,造成上述問題的出現,後期可以通過配置的形式避免該現象的發生,但是效率非常低下。實際業務中,只需要給用戶一個合理的提示就行了。

lupdate操作可以將DO轉換為PO,但是如果此時Session範圍內存在有相同OID的PO對象,此時將報錯

l總結:任意時間,同一個Session範圍內,不管通過何種方式,如果兩個PO具有了同樣的OID,那麽Hibernate無法區分兩個對象,此時將報錯


lupdate操作將DO轉化為PO時,如果Session範圍內存在有相同OID的PO,那麽程序將報錯。如果要將DO繼續轉化為PO,可以將兩個對象合並成一個,使用merge操作可以完成對象的合並。

lmerge操作是將當前操作的DO屬性,合並到OID相同的PO上,最終屬性以最後一次修改的為準。如果沒有與DO的OID相同的PO,那麽merge操作將執行update操作,將DO轉化為PO

?存在相同OID的PO,DO合並屬性到PO

?不存在相同OID的PO,DO轉化為PO

s.merge(um);


lsaveOrUpdate操作是根據對象的狀態執行對應操作

?TO執行save操作

?PO無任何操作

?DO執行update操作

l註意:TO的判定標準

?對象的OID為null

?在hbm.xml文件中,為id元素指定unsaved-value屬性值,且對象的OID的值與其相同

技術分享圖片


lget與load方法都可以根據傳入的OID值從數據庫中獲取對應的記錄信息,並轉換為PO

lget與load讀取時加載策略不同(前面已講解)

lget與load獲取數據的區別:

?當DB中不存在get操作獲取的OID數據時返回null

?當DB中不存在load操作獲取的OID數據時,拋異常

?load方法返回的不是模型對象,而是模型對象的代理對象,因此對於模型類不能使用final修飾,否則將無法創建代理對象


ldelete操作可以從數據庫表中刪除一條對應的記錄

ldelete操作運行原理

?delete操作刪除某個對象時,只能對PO進行操作

?如果是DO,首先關聯到Session,將DO轉化為PO

?TO無法刪除

?執行delete操作,在Session範圍內對待刪除的數據進行刪除標記的添加,此時,該對象已經被標記為被刪除對象,但還未執行刪除語句,數據庫中還存在該記錄

?刷新緩存時,執行真正的DELETE語句

hibernate框架學習之一級緩存