Hibernate緩存機制

爲什麼要用Hibernate緩存?

Hibernate是一個持久層框架,經常訪問物理數據庫。使用緩存機制,是爲了降低應用程序對物理數據源訪問的頻次,從而提高應用程序的運行性能。

緩存內的數據是對物理數據源中的數據的複製,應用程序在運行時從緩存讀寫數據,在特定的時刻或事件會同步緩存和物理數據源的數據。

Hibernate緩存包括一級緩存和二級緩存。


 

Hibernate中對象三種狀態

瞬時態:transient,session沒有緩存對象,數據庫也沒有對應記錄。

OID特點:沒有值

持久態:persistent,session緩存對象,數據庫最終會有記錄。(事務沒有提交)

OID特點:有值

脫管態:detached,session沒有緩存對象,數據庫有記錄。

OID特點:有值

 

對象狀態轉換圖

 

 


Hibernate一級緩存

Hibernate一級緩存又稱爲“Session的緩存”,是默認開啓的。Session內置不能被卸載,Session的緩存是事務範圍的緩存(Session對象的生命週期通常對應一個數據庫事務或者一個應用事務)。一級緩存中,持久化類的每個實例都具有唯一的OI

證明一級緩存。

@Test
public void demo02(){
    //證明一級緩存
    Session session = factory.openSession();
    session.beginTransaction();
    
    //1 查詢 id = 1
    User user = (User) session.get(User.class, 1);
    System.out.println(user);
    //2 再查詢 -- 不執行select語句,將從一級緩存獲得
    User user2 = (User) session.get(User.class, 1);
    System.out.println(user2);
    
    session.getTransaction().commit();
    session.close();
}

 

可以調用方法清除一級緩存(可以是對特定對象的)。

//清除
//session.clear();
session.evict(user);

 

一級緩存的管理

evit(Object obj)  將指定的持久化對象從一級緩存中清除,釋放對象所佔用的內存資源,指定對象從持久化狀態變爲脫管狀態,從而成爲遊離對象。

clear()  將一級緩存中的所有持久化對象清除,釋放其佔用的內存資源。

contains(Object obj) 判斷指定的對象是否存在於一級緩存中。

flush() 刷新一級緩存區的內容,使之與數據庫數據保持同步。

 

一級緩存的快照原理

* 使用id進行查詢數據庫,將查詢得到的結果放置到session一級緩存中,同時複製一份數據,放置到session的快照中

* 當使用tr.commit()的時候,同時清理session的一級緩存(flush)

* 當清理session一級緩存的時候,會使用OID判斷一級緩存中對象和快照中的對象進行比對

* 如果2個對象(一級緩存的對象和快照的對象)中的屬性發生變化,則執行update語句,此時更新數據庫,更新成一級緩存中的數據

* 如果2個對象中的屬性不發生變化,此時不執行update語句

 

作用:引入快照可以保證數據一致性,避免不要的update,減少數據庫的訪問壓力。


Hibernate二級緩存

Hibernate二級緩存又稱爲“SessionFactory的緩存”。緩存被應用範圍內的所有session共享,不同的session可以共享。這些session有可能是併發訪問緩存,因此必須對緩存進行更新。緩存的生命週期依賴於應用的生命週期,應用結束時,緩存也就結束了生命週期,二級緩存存在於應用程序範圍。

二級緩存是可選的,是一個可配置的插件,默認下SessionFactory不會啓用這個插件。

有如下代碼

@Test
public void testCache2() {
Session session1 = sf.openSession();//獲得Session1
session1.beginTransaction();
Category c = (Category)session1.load(Category.class, 1);
System.out.println(c.getName());
 
 
session1.getTransaction().commit();
session1.close();
 
Session session2 = sf.openSession();//獲得Session2
session2.beginTransaction();
Category c2 = (Category)session2.load(Category.class, 1);
System.out.println(c2.getName());
session2.getTransaction().commit();
session2.close();
}

不開啓二級緩存的情況下,因爲一個session不能取其他session的緩存,在上面的代碼中,我們重啓一個Session,第二次調用load或者get方法檢索同一個對象的時候會重新查找數據庫,會發select語句信息。如果要共享session的緩存,那麼可以考慮開啓二級緩存。

 

適合存放在二級緩存的數據

(1)經常被訪問

(2)改動不大

(3)數量有限

(4)不是很重要的數據,允許出現偶爾併發的數據。 

 

在Hibernate中使用EhCache來支持二級緩存

<!-- EHCache的配置,hibernate.cfg.xml -->
<hibernate-configuration>
    <session-factory>
       <!-- 設置二級緩存插件EHCache的Provider類-->
       <property name="hibernate.cache.provider_class">
          org.hibernate.cache.EhCacheProvider
       </property>
       <!-- 啓動"查詢緩存" -->
       <property name="hibernate.cache.use_query_cache">
          true
       </property>
    </session-factory>
  </hibernate-configuration>

<!-- ehcache.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<ehcache>
    <!--
        緩存到硬盤的路徑
    -->
    <diskStore path="d:/ehcache"></diskStore>
    <!--
        默認設置
        maxElementsInMemory : 在內存中最大緩存的對象數量。
        eternal : 緩存的對象是否永遠不變。
        timeToIdleSeconds :可以操作對象的時間。
        timeToLiveSeconds :緩存中對象的生命週期,時間到後查詢數據會從數據庫中讀取。
        overflowToDisk :內存滿了,是否要緩存到硬盤。
    -->
    <defaultCache maxElementsInMemory="200" eternal="false"
        timeToIdleSeconds="50" timeToLiveSeconds="60" overflowToDisk="true"></defaultCache>
    <!--
        指定緩存的對象。
        下面出現的的屬性覆蓋上面出現的,沒出現的繼承上面的。
    -->
    <cache name="com.suxiaolei.hibernate.pojos.Order" maxElementsInMemory="200" eternal="false"
        timeToIdleSeconds="50" timeToLiveSeconds="60" overflowToDisk="true"></cache>
</ehcache>

 

二級緩存實現原理

我們可以把緩存看做是一個Map對象,它的Key用於存儲對象OID,Value用於存儲POJO。首先,當我們使用Hibernate從數據庫中查詢出數據,獲取檢索的數據後,Hibernate將檢索出來的對象的OID放入緩存中key 中,然後將具體的POJO放入value中,等待下一次再次向數據查詢數據時,Hibernate根據你提供的OID先檢索一級緩存,若有且配置了二級緩存,則檢索二級緩存,如果還沒有則才向數據庫發送SQL語句,然後將查詢出來的對象放入緩存中。

 

相關博文:

http://blog.csdn.net/tanga842428/article/details/52698657

https://www.jianshu.com/p/50964e92c5fb

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章