理解Session緩存


1. Session緩存
   為了讓對象A一直處於生命周期中,要么對象A被顯示引用,要么對對象A的引用保存在始終處於生命周期中的對象B中,直到對象B的生命周期結束而結束。在Session接口的實現中包含了一系列的Java集合,這些集合用於保存對持久化對象的引用,因此這些Java集合就構成了Session的緩存。
   當調用Session接口的save()方法持久化一個對象時,該對象被加入到Session緩存中,以后只要Session緩存沒有被清空,該對象將一直處於生命周期中。
   當調用Session接口的get()方法試圖裝載一個持久化對象時,Session首先判斷緩存中是否存在這個對象,若存在則返回,若不存在則從數據庫中檢索。

 

2. Session緩存的作用

(1) 減少訪問數據庫的頻率。應用程序從緩存中讀取持久化對象的速度顯然優於從數據庫中檢索數據的速度。

(2) 當緩存中的持久化對象之間存在循環關聯關系時,Session會保證不出現訪問對象圖的死循環,以及由死循環引發的JVM堆棧溢出。

(3) 保證數據庫中的相關記錄與緩存中的記錄同步。Session在清理緩存的時,會自動進行臟數據檢查(dirty-check),如果發現Session緩存中的對象與數據庫中相應記錄不一致,則會按最新的對象屬性更新數據庫。

3. 清理緩存的機制
        為減少訪問數據庫的次數,當Session緩存中對象的屬性發生變化時,並不會及時清理緩存及執行相關的SQL Update語句,而是在特定的時間點把相關的SQL合並為一條SQL語句才清理緩存。
 Transaction transaction = hibernateSession.beginTransaction();
 Customers c = (Customers)hibernateSession.get(Customers.class, new Long(3));
 c.setName("Mike");
 c.setName("Jone");
 transaction.commit();//自動清理緩存,執行一條Update語句,提交事務
         在默認情況下,Session會在以下時間點清理緩存(保證Session緩存中對象與數據庫記錄數據的一致性。):
(1) org.hibernate.Transaction.commit():先清理緩存再提交事務;
(2) 執行持久化查詢操作時,如果緩存中的持久化對象的屬性已發生變化,則先清理緩存以便與數據庫中的記錄保持同步;
(3) 顯示調用Session.flush()時,會清空緩存。
 Transaction transaction = hibernateSession.beginTransaction();
 Customers c = (Customers)hibernateSession.get(Customers.class, new Long(3));
 c.setName("ChengDong");
 hibernateSession.flush();// 顯示清理緩存,執行update語句
 c.setName("Mike");
 transaction.commit();// 自動清理緩存,執行update語句,提交事務
       注意:commit()和flush()方法區別在於:后者進行清理緩存的操作,執行一系列SQL語句,但不會提交事務;前者會先調用flush()方法,然后提交事務。提交事務也就意味着對數據庫所做的

更新將永久保存下來。
        除了默認的清理緩存的方式外,還可以通過Session.setFlushMode()方法顯示設定清理緩存的時間點,包括FlushMode.AUTO、FlushMode.NEVER、FlushMode.COMMIT,具體用法詳查資料。

4. Java對象在持久化層的狀態:
(1) Transient(臨時狀態):new語句創建、沒有被持久化且不在Session緩存中。處於這種狀態的對象被稱為臨時對象;
(2) Persistent(持久化狀態):已被持久化且已加入到Session緩存中。處於這種狀態的對象被稱為持久化對象;
(3) Detached(游離狀態):已被持久化,但不處於Session的緩存中。處於這種狀態的對象被稱為游離對象。
持久化對象的特征:
(1) OID不為NULL;
(2) 位於一個Session實例的緩存中;
(3) 持久化對象與數據庫中的相關記錄對應;
(4) Session在清理緩存時,會根據持久化對象的屬性變化來同步更新數據庫。
   Session的許多方法都能使Java對象進入持久化狀態:
(1) save():臨時對象---> 持久化對象;
(2) load()/get():返回的對象總是處於持久化狀態;
(3) list():返回的list對象都是持久化對象;
(4) update()/saveOrUpdate()/lock():游離對象--->持久化對象。
   Hibernate保證同一個Session實例的緩存中,數據庫中的每條記錄只對應唯一的持久化對象,因此來自於同一個session實例緩存中的持久化對象的引用變量必然相同,即:
      Session hibernateSession = sessionFactory.openSession();
      Session hibernateSession2 = sessionFactory.openSession();
 
     Transaction transaction = hibernateSession.beginTransaction();
     Transaction transaction2 = hibernateSession2.beginTransaction();
     Customers a = (Customers)hibernateSession.get(Customers.class, new Long(3));
     Customers b = (Customers)hibernateSession.get(Customers.class, new Long(3));
     Customers c = (Customers)hibernateSession2.get(Customers.class, new Long(3));
     // 同一Session實例的緩存中僅存在唯一一個與數據庫記錄對應的持久化對象
     System.out.println(a == b);// true
     System.out.println(a == c);// false
 
     transaction.commit();
     transaction2.commit();
     hibernateSession.close();
     hibernateSession2.close();
   在實際應用中,應避免一個Java對象同時位於多個Session實例中緩存中,否則這會導致重復執行SQL語句,並且極易出現高並發問題。

5. Session的一些持久化操作

(1) save

       該操作首先將臨時對象轉化為持久化對象,並加入到Session緩存中;其次根據映射文件中給定的標識符生成器,為持久化對象分配唯一一個OID。save()方法僅用來持久化臨時對象,在程序中不應該把持久化對象和游離對象傳給save()。

       注:save()操作僅僅是將Java對象的臨時狀態轉化為持久化狀態,並未立即執行insert語句,待需要清理緩存時才會執行insert語句。如果在save()方法改變了持久化對象的屬性,則在清理緩存時不僅要執行insert語句,還要執行update語句,例如:

Transaction trasaction = session.beginTransaction();
 Customers c = new Customers();
 c.setName("testSave");
 session.save(c);// 此步完成對象持久化和持久化對象OID的分配
 c.setName("testCache");
 trasaction.commit();// 自動清理緩存

控制台打印的SQL為:

Hibernate: insert into customers (name, ID) values (?, ?)
Hibernate: update customers set name=? where ID=?

(2) Session的get()和load()方法

      這兩個操作都是根據OID單數據加載持久化對象。它們的不同之處在於:當數據庫中不存在與OID對應的記錄時,load()會直接拋出org.hibernate.ObjectNotFoundException,而get()則返回null。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM