NHibernate之旅(23):探索NHibernate二級緩存(上)

NHibernate之旅(23):探索NHibernate二級緩存(上)

本節內容

  • 引入
  • 介紹NHibernate二級緩存
  • NHibernate二級緩存提供程序
  • 實現NHibernate二級緩存
  • 結語

引入

上一篇我介紹了NHibernate內置的一級緩存即ISession緩存。這篇我們來了解下NHibernate二級緩存即ISessionFactory級別緩存。二級緩存是可擴展的,在NHibernate Contrib上提供了第三方NHibernate二級緩存提供程序。

介紹NHibernate二級緩存

NHibernate二級緩存由ISessionFactory創建,可以被所有的ISession共享。

在NHibernate中,當我們啓用NHibernate二級緩存。使用ISession進行數據操作時,NHibernate首先從內置緩存(一級緩存)中查找是否存在需要的數據,如果內置緩存不存在需要的數據,則查詢二級緩存,如果二級緩存中存在所需數據,則直接使用緩存中數據,否則從數據庫中查詢數據並放入緩存中。

NHibernate本身提供了一個基於Hashtable的HashtableCache緩存,但是功能非常有限而且性能比較差,不適合在大型應用程序使用,我們可以使用第三方緩存提供程序作爲NHibernate二級緩存實現。

但是,使用緩存的缺點就是如果緩存策略設置不當,NHibernate不知道其它應用程序對數據庫的修改及時更新緩存。因此,建議只對系統經常使用、數據量不大且不會被其它應用程序修改的只讀數據(或很少被修改的數據)使用緩存。

NHibernate二級緩存提供程序

NHibernate提供了NHibernate.Cache.ICacheProvider接口用來支持第三方緩存提供程序實現。開發緩存提供程序時,需要實現該接口作爲NHibernate和緩存實現直接的適配器。NHibernate提供了常見的緩存提供程序的內置適配器,這些適配器都實現了NHibernate.Cache.ICacheProvider接口。

除了NHibernate本身提供的一個基於Hashtable的HashtableCache緩存,在NHibernate Contrib上提供了六種第三方NHibernate二級緩存提供程序,完全開源的。我們直接下載其程序集引用到我們的項目中就可以使用了。

  • NHibernate.Caches.MemCache
  • NHibernate.Caches.Prevalence
  • NHibernate.Caches.SharedCache
  • NHibernate.Caches.SysCache
  • NHibernate.Caches.SysCache2
  • NHibernate.Caches.Velocity

實現NHibernate二級緩存

NHibernate二級緩存是一個可插拔的組件。在默認情況下,NHibernate不啓動二級緩存。如果要使用二級緩存則需要在NHibernate配置文件中顯式的啓用二級緩存。NHibernate二級緩存可以分別爲每一個具體的類和集合配置應用級或分佈式緩存。

緩存併發策略

提示一下,在NHibernate官方文檔中有介紹,詳情請參考NHibernate官方文檔。當兩個獨立的事務同時訪問數據庫時,可能產生丟失更新、不可重複讀等併發問題。同樣,當兩個併發事務同時訪問緩存時,也有可能產生各種併發問題。因此,在緩存級別也需要設置相應的併發訪問策略。

NHibernate內置四種併發訪問策略:

  • read-only:只讀緩存。適用於只讀數據。可用於羣集中。
  • read-write:讀寫緩存。
  • nonstrict-read-write:非嚴格讀寫緩存。不保證緩存與數據庫的一致性。
  • transactional:事務緩存。提供可重複讀的事務隔離級別。

我們動手實現二級緩存吧~~~

Step1:配置第三方緩存提供程序

我們在NHibernate配置文件中通過cache.provider_class屬性顯式指定緩存實現,屬性值爲緩存適配器的具體類名。如果你使用上面的第三方緩存提供程序,還需要配置緩存提供程序本身。這裏我設置NHibernate本身提供了一個基於Hashtable的HashtableCache緩存。

<property name="cache.provider_class">NHibernate.Cache.HashtableCacheProvider</property>

Step2:顯式啓用二級緩存

在NHibernate配置文件中使用cache.use_second_level_cache屬性顯式啓用二級緩存,參數爲Bool值,這裏啓用設置爲true。

<property name ="cache.use_second_level_cache">true</property>

Step3:配置第三方緩存提供程序本身

如果你使用第三方緩存提供程序,那麼需要對第三方緩存提供程序本身進行配置,需要詳細配置第三方緩存提供程序緩存屬性:保存時間、過期時間、可以緩存對象數量。這裏我就使用NHibernate本身提供的HashtableCache緩存,所以這一步就省略了。

Step4:爲每一個持久化類和集合指定相應的緩存策略

方法一:在映射文件中通過<cache>元素配置類和集合的緩存策略,在Class元素或者集合元素中添加<cache>元素進行配置。注意:<cache>元素必須在<id>元素之前。

<cache usage="read-only|read-write|nonstrict-read-write" region="默認類或集合名稱"/>

方法二:在NHibernate配置文件hibernate.cfg.xml中通過<class-cache>元素和<collection-cache>元素分別配置類和集合的緩存策略。

我還是建議大家使用NHibernate配置文件定義緩存策略,這樣可以避免在各個映射文件配置緩存定義而增大維護難度。

指定類:

<class-cache class="類名稱" region="默認類名稱" include="all|non-lazy"
             usage="read-only|read-write|nonstrict-read-write|transactional" />

指定集合:

<collection-cache collection ="集合名稱" region="默認集合名稱"
                  usage="read-only|read-write|nonstrict-read-write|transactional"/>

具體意義是:

  • region:可選,默認值爲類或集合的名稱,用來指定二級緩存的區域名,對應於緩存實現的一個命名緩存區域。
  • include:可選,默認值爲all,當取non-lazy時設置延遲加載的持久化實例的屬性不被緩存。
  • usage:聲明緩存同步策略,就是上面說明的四種緩存策略。

配置文件和映射文件定義不一樣,不知道是不是BUG。

Step5:開始測試

在測試之前,我們先看看上面的步驟我們完成了哪些內容。我貼出具體代碼:

代碼片段1:NHibernate配置文件:

<?xml version="1.0" encoding="utf-8"?>
<hibernate-configuration  xmlns="urn:nhibernate-configuration-2.2" >
    <session-factory name="NHibernateSample.DAL.Test">
    <!--
       配置二級緩存實例文件
       作者:李永京(YJingLee's Blog)
       出處:http://lyj.cnblogs.com
    -->
    <property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property>
    <property name="connection.connection_string">
      Data Source=./SQLEXPRESS;Initial Catalog=NHibernateSample;
      Integrated Security=True;Pooling=False</property>
    <property name="adonet.batch_size">10</property>
    <property name="show_sql">true</property>
    <property name="dialect">NHibernate.Dialect.MsSql2005Dialect</property>
    <property name="use_outer_join">true</property>
    <property name="query.substitutions">true 1, false 0, yes 'Y', no 'N'</property>
    <!--1.配置二級緩存提供程序-->
    <property name="cache.provider_class">NHibernate.Cache.HashtableCacheProvider</property>
    <!--2.顯式啓用二級緩存-->
    <property name ="cache.use_second_level_cache">true</property>
    <!--4.啓動查詢緩存(注:下一篇內容:http://lyj.cnblogs.com)-->
    <property name="cache.use_query_cache">true</property>
    <mapping assembly="DomainModel"/>
    <!--3.配置映射的二級緩存-->
    <class-cache class="DomainModel.Entities.Customer,DomainModel" usage="read-write"/>
    </session-factory>
</hibernate-configuration>

代碼片段2:Customer.hbm.xml映射文件:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" 
                   assembly="DomainModel" namespace="DomainModel">
    <!--
       配置二級緩存映射文件
       作者:李永京(YJingLee's Blog)
       出處:http://lyj.cnblogs.com
    -->
  <class name ="DomainModel.Entities.Customer,DomainModel" 
         table="Customer">
    <cache usage="read-write"/>
    <id name="CustomerId" type="Int32" unsaved-value="0">
      <generator class ="native"></generator>
    </id>
    <version name="Version" type="integer" unsaved-value="0"/>    
    <component name="Name" class="DomainModel.Entities.Name,DomainModel">
      <property name="Firstname"/>
      <property name ="Lastname"/>
    </component> 
    <set name="Orders" table="`Order`" generic="true" inverse="true">
      <cache usage="read-only"/>
      <key column="Customer" foreign-key="FK_CustomerOrders"/>
      <one-to-many class="DomainModel.Entities.Order,DomainModel"/>
    </set>
  </class>
</hibernate-mapping>

Step6:測試代碼

在不同Session中獲取實體:

[Test]
public void SessionFactoryCacheTest()
{
     using (_session)
    {
        Console.WriteLine("--Session 1--讀取持久化實例--");
        Customer customer1 = _session.Get<Customer>(1);
        Assert.IsNotNull(customer1);
    }
    ResetSession();
    using (_session)
    {
        Console.WriteLine("--Session 2--讀取持久化實例--");
        Customer customer2 = _session.Get<Customer>(1);
        Assert.IsNotNull(customer2);
    }
}

分析一下:在第一次查詢數據時,由於一級、二級緩存中都不存在需要的數據,這時NHibernate從數據庫中查詢數據。第二次讀取同一數據,NHibernate首先從內置緩存(一級緩存)中查找是否存在所需要數據,由於不是在同一個ISession中,所以內置ISession緩存中不存在所需數據,NHibernate則查詢二級緩存,這時由於第一次查詢了這條數據,所以在二級緩存中存在所需數據,則直接使用緩存中數據。看看輸出結果吧:

啓用NHibernate二級緩存測試

結語

好了,這篇就到這裏吧!我們初步認識了NHibernate二級緩存,並用一個查詢例子說明了一切,但是關於二級緩存還有很多內容,比如你修改、刪除數據時,二級緩存是什麼策略呢?我們如果使用查詢緩存呢?如何管理NHibernate二級緩存呢?這就在下一篇揭曉吧。

發佈了85 篇原創文章 · 獲贊 2 · 訪問量 16萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章