1. 程式人生 > >Hibernate之快取機制!!!!!!

Hibernate之快取機制!!!!!!

快取:

  是計算機領域的概念,它介於應用程式和永久性資料儲存源之間。

快取:

  一般人的理解是在記憶體中的一塊空間,可以將二級快取配置到硬碟。用白話來說,就是一個儲存資料的容器。我們關注的是,哪些資料需要被放入二級快取。

快取作用:

  降低應用程式直接讀寫資料庫的頻率,從而提高程式的執行效能。快取中的資料是資料儲存源中資料的拷貝。快取的物理介質通常是【記憶體】。

快取分類:

  1.Session快取(又稱作事務快取):Hibernate內建的,不能卸除。

  2.SessionFactory快取(又稱作應用快取):使用第三方外掛,可插拔。

快取範圍:

  快取只能被當前Session物件訪問。

  快取的生命週期依賴於Session的生命週期,當Session被關閉後,快取也就結束生命週期。

  快取被應用範圍內的所有session共享,不同的Session可以共享。

  這些session有可能是併發訪問快取,因此必須對快取進行更新。

  快取的生命週期依賴於應用的生命週期,應用結束時,快取也就結束了生命週期,二級快取存在於應用程式範圍。

 

一級快取:

1.當我們通過session的save、update、saveOrUpdate方法進行操作時,如果一級快取中沒有物件,那麼會從資料庫中查詢到這些物件,並存儲到一級快取中。
2.當我們通過session的load、get、Query的list等方法進行操作時,會先判斷一級快取中是否存在資料,如果沒有才會從資料庫獲取,並且將查詢的資料儲存到一級快取中。
3.當呼叫session的close方法時,session快取將清空。

public class SessionFactoryUtil {

//    private static Configuration configuration;
//
//    private static SessionFactory factory;
//
//    static{
//        //預設載入專案根目錄下的hibernate.cfg.xml
//        configuration=new Configuration().configure();
//        factory=configuration.buildSessionFactory();
//    }
//    public static synchronized Session getCureentSession()
// { // return factory.getCurrentSession(); // } //執行緒變數 get set static ThreadLocal<Session> tlSession=new ThreadLocal<Session>(); //得有SessionFactory public static SessionFactory factory; static Configuration cfg=null; static { cfg=new Configuration().configure("hibernate.cfg.xml"); factory=cfg.buildSessionFactory(); } //01.獲取連線 public static Session getSession(){ //01.從執行緒變數中嘗試獲取 Session session = tlSession.get(); if (session==null){ //使用者第一次獲取連線:發現執行緒變數中沒有session,建立一個,並且放入執行緒變數 session = factory.openSession(); tlSession.set(session); } return session; } //02.釋放連線 public static void closeSession(){ Session session = tlSession.get(); if (session!=null){ //執行緒變數set成null tlSession.set(null); session.close(); } }
public class AppTest 
{
    private static Transaction transaction;
    private static Session session;

    @Before
    public void one(){

        //建立一個會話
        session= SessionFactoryUtil.getSession();
        //開啟事務
        transaction=session.beginTransaction();

    }

    @After
    public void close(){
        transaction.commit();
    }

 /**
     * 是否存在一級快取
     */

    @Test
    public void test13(){
        Criteria criteria=session.createCriteria(District.class);
        District load = (District) session.load(District.class, 1);
        System.out.println(load.getName());
        System.out.println("==================");
        District load2 = (District) session.get(District.class, 1);
        System.out.println(load2.getName());
    }

  在這裡控制檯輸出一條SQL時證明一級快取存在

 

二級快取:

  SessionFactory級別的快取,可以跨越Session存在,可以被多個Session所共享。

  在cfg.xml檔案中配置相關的節點

 

<!--開啟hibernate需要的2級快取 -->
<property name="cache.use_second_level_cache">true</property>
<property name="cache.provider_class">org.hibernate.cache.EhCacheProvider</property>

<!--指定那個類需要開啟二級快取 -->
<class-cache class="com.msss.pojo.District" usage="read-write"></class-cache>

ehcache.xml 配置
<ehcache>

    <!-- Sets the path to the directory where cache .data files are created.

         If the path is a Java System Property it is replaced by
         its value in the running VM.

         The following properties are translated:
         user.home - User's home directory
         user.dir - User's current working directory
         java.io.tmpdir - Default temp file path -->
  
  <!--指定二級快取存放在磁碟上的位置-->
    <diskStore path="user.dir"/>  

  <!--我們可以給每個實體類指定一個對應的快取,如果沒有匹配到該類,則使用這個預設的快取配置-->
    <defaultCache
        maxElementsInMemory="10000"  //在記憶體中存放的最大物件數
        eternal="false"         //是否永久儲存快取,設定成false
        timeToIdleSeconds="120"    
        timeToLiveSeconds="120"    
        overflowToDisk="true"     //如果物件數量超過記憶體中最大的數,是否將其儲存到磁碟中,設定成true
        />
  
  <!--
    1、timeToLiveSeconds的定義是:以建立時間為基準開始計算的超時時長;
    2、timeToIdleSeconds的定義是:在建立時間和最近訪問時間中取出離現在最近的時間作為基準計算的超時時長;
    3、如果僅設定了timeToLiveSeconds,則該物件的超時時間=建立時間+timeToLiveSeconds,假設為A;
    4、如果沒設定timeToLiveSeconds,則該物件的超時時間=max(建立時間,最近訪問時間)+timeToIdleSeconds,假設為B;
    5、如果兩者都設定了,則取出A、B最少的值,即min(A,B),表示只要有一個超時成立即算超時。
  -->

  <!--可以給每個實體類指定一個配置檔案,通過name屬性指定,要使用類的全名-->
    <cache name="com.xiaoluo.bean.Student"
        maxElementsInMemory="10000"
        eternal="false"
        timeToIdleSeconds="300"
        timeToLiveSeconds="600"
        overflowToDisk="true"
        />

    <cache name="sampleCache2"
        maxElementsInMemory="1000"
        eternal="true"
        timeToIdleSeconds="0"
        timeToLiveSeconds="0"
        overflowToDisk="false"
        /> -->


</ehcache>

 

什麼樣的資料適合存放到第二級快取中?   
  1.很少被修改的資料   
  2.不是很重要的資料,允許出現偶爾併發的資料   
  3.不會被併發訪問的資料   
  4. 常量資料   

不適合存放到第二級快取的資料?   
  1. 經常被修改的資料   
  2.絕對不允許出現併發訪問的資料,如財務資料,絕對不允許出現併發   
  3.與其他應用共享的資料。

 

 

一級快取與二級快取的對比圖:

 

一級快取

二級快取

存放資料的形式

相互關聯的持久化物件

物件的散裝資料

快取的範圍

事務範圍,每個事務都擁有單獨的一級快取

程序範圍或叢集範圍,快取被同一個程序或叢集範圍內所有事務共享

併發訪問策略

由於每個事務都擁有單獨的一級快取不會出現併發問題,因此無須提供併發訪問策略

由於多個事務會同時訪問二級快取中的相同資料,因此必須提供適當的併發訪問策略,來保證特定的事務隔離級別

資料過期策略

處於一級快取中的物件永遠不會過期,除非應用程式顯示清空或者清空特定物件

必須提供資料過期策略,如基於記憶體的快取中物件的最大數目,允許物件處於快取中的最長時間,以及允許物件處於快取中的最長空閒時間

物理介質

記憶體

記憶體和硬碟,物件的散裝資料首先存放到基於記憶體的快取中,當記憶體中物件的數目達到資料過期策略的maxElementsInMemory值,就會把其餘的物件寫入基於硬碟的快取中

快取軟體實現

在Hibernate的Session的實現中包含

由第三方提供,Hibernate僅提供了快取介面卡,用於把特定的快取外掛整合到Hibernate中

啟用快取方式

只要通過Session介面來執行儲存,更新,刪除,載入,查詢,Hibernate就會啟用一級快取,對於批量操作,如不希望啟用一級快取,直接通過JDBCAPI來執行

使用者可以再單個類或類的單個集合的粒度上配置第二級快取,如果類的例項被經常讀,但很少被修改,就可以考慮使用二級快取,只有為某個類或集合配置了二級快取,Hibernate在執行時才會把它的例項加入到二級快取中

使用者管理快取的方式

一級快取的物理介質為記憶體,由於記憶體的容量有限,必須通過恰當的檢索策略和檢索方式來限制載入物件的數目,Session的evit()方法可以顯示的清空快取中特定物件,但不推薦

二級快取的物理介質可以使記憶體和硬碟,因此第二級快取可以存放大容量的資料,資料過期策略的maxElementsInMemory屬性可以控制記憶體中的物件數目,管理二級快取主要包括兩個方面:選擇需要使用第二級快取的持久化類,設定合適的併發訪問策略;選擇快取介面卡,設定合適的資料過期策略。SessionFactory的evit()方法也可以顯示的清空快取中特定物件,但不推薦