程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> NHibernate之旅(24):探索NHibernate二級緩存(下)

NHibernate之旅(24):探索NHibernate二級緩存(下)

編輯:關於.NET

本節內容

引入

使用NHibernate二級緩存

啟用緩存查詢

管理NHibernate二級緩存

結語

引入

呵呵,今天收到了微軟“最有影響力開發者”禮包,很高興自己榮獲“微軟最有影響力開發者”稱號(詳情請進),這篇我還繼續上一篇的話題聊聊NHibernate二級緩存剩下的內容,比如你修改、刪除數據時,二級緩存是什麼策略呢?我們如果使用緩存查詢呢?如何管理NHibernate二級緩存呢?

使用NHibernate二級緩存

不知道具體配置的請轉到NHibernate之旅系列文章導航觀看上一篇的內容,這篇我們再寫幾個測試,來看看NHibernate二級緩存一些細節:

測試1:更新數據

當我們啟用二級緩存時,如果第一次把數據查詢出來,然後修改了這個數據,這時二級緩存中的數據是什麼呢?我們寫一個測試看看究竟吧:

[Test]
public void SessionFactoryCacheUpdateTest()
{
  string firstname="YJingLee";
  using (_session)
  {
    using (var tx = _session.BeginTransaction())
    {
      Console.WriteLine("第一次讀取持久化實例");
      Customer customer1 = _session.Get<Customer>(1);
      Console.WriteLine("更新持久化實例");
      customer1.Name.Firstname =firstname;
      tx.Commit();
    }
  }
  ResetSession();
  Console.WriteLine("第二次讀取持久化實例");
  using (_session)
  {
    Customer customer2 = _session.Get<Customer>(1);
    Console.WriteLine("新FirstName為:{0}",customer2.Name.Firstname);
    Assert.AreEqual(customer2.Name.Firstname, firstname);
  }
}

輸出結果:

分析一下:在第一次查詢數據時,由於一級、二級緩存中都不存在需要的數據,這時NHibernate從數據庫中查詢數據。我們修改這條數據並提交到數據庫中,NHibernate執行一條更新語句,由於我們設置了讀寫緩存策略,NHibernate更新了二級緩存中的數據內容,第二次讀取這條數據,NHibernate首先從內置緩存(一級緩存)中查找是否存在所需要數據,由於不是在同一個ISession中,所以內置ISession緩存中不存在所需數據,NHibernate則查詢二級緩存,這時由於第一次查詢了這條數據,所以在二級緩存中存在所需數據,則直接使用緩存中數據。這時緩存中的數據也是更新的。

至於刪除、插入數據我想也是類似的。這裡我就不寫測試了。

啟用緩存查詢

在NHibernate中,除了緩存持久化類和集合外,查詢結果集也可以緩存。如果程序中經常使用同樣的條件查詢數據,則可以使用查詢緩存。在配置文件中可以指定啟動查詢緩存

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

查詢緩存後,NHibernate將創建兩個緩存區域。一個用於保存查詢結果集,由NHibernate.Cache.StandardQueryCache實現。一個用來保存最近更新的查詢表的時間截,由NHibernate.Cache.UpdateTimestampsCache實現。

查詢緩存中的結果集並不是永久有效的。當緩存的查詢語句對應的數據庫發生改變時,該緩存結果隨之失效。因而對大多數查詢而言,查詢緩存的益處不是很大,所以NHibernate在默認情況下不對查詢進行緩存。

如果需要對查詢緩存,還需要顯式的使用IQuery.SetCacheable(true)方法。IQuery調用這個方法後,NHibernate將根據查詢語句、查詢參數、結果集起始范圍等信息組成一個IQueryKey。接著根據這個IQueryKey到查詢緩存中查找相應數據,查詢成功則直接返回查找結果。否則,查詢數據庫,獲取結果集,並把結果集根據IQueryKey放入查詢緩存。如果IQueryKey數據發生改變(增加、刪除、修改等),這些IQueryKey及其對象的結果集將從緩存中刪除。

測試2:顯式啟用緩存查詢

這個例子顯式使用IQuery.SetCacheable(true)方法緩存查詢結果,第二次查詢相同條件時,直接從緩存查詢中讀取。

[Test]
public void QueryCacheTest()
{
  using (_session)
  {
    Console.WriteLine("第一次查詢某數據,顯式緩存查詢結果");
    IList<Customer> customers =
      _session.CreateQuery("from Customer c where c.CustomerId > 2")
      .SetCacheable(true)
      .List<Customer>();
    Assert.AreEqual(11, customers.Count);
  }
  ResetSession();
  using (_session)
  {
    Console.WriteLine("第二次查詢某數據,顯式緩存查詢結果");
    IList<Customer> customers =
      _session.CreateQuery("from Customer c where c.CustomerId > 2")
      .SetCacheable(true)
      .List<Customer>();
    Assert.AreEqual(11, customers.Count);
  }
}

看看結果

由於我們顯式緩存查詢結果,在第二次查詢時,直接使用二級緩存中的結果集。

測試3:指定命名緩存區域

我們還可以使用.SetCacheRegion("cacheRegion")給查詢緩存指定了特定的命名緩存區域,該查詢緩存的緩存策略將由二級緩存的命名區域負責:

[Test]
public void QueryCacheTest()
{
  using (_session)
  {
    Console.WriteLine("第一次查詢某數據,顯式緩存查詢結果");
    IList<Customer> customers =
      _session.CreateQuery("from Customer c where c.CustomerId > 2")
      .SetCacheable(true)
      .SetCacheRegion("queryCache")
      .List<Customer>();
    Assert.AreEqual(11, customers.Count);
  }
  ResetSession();
  using (_session)
  {
    Console.WriteLine("第二次查詢某數據,顯式緩存查詢結果");
    IList<Customer> customers =
      _session.CreateQuery("from Customer c where c.CustomerId > 2")
      .SetCacheable(true)
      .SetCacheRegion("queryCache")
      .List<Customer>();
    Assert.AreEqual(11, customers.Count);
  }
}

測試結果說明:第一次查詢出來的結果集被存儲在名為queryCache的緩存區域,第二次同樣在這個緩存區域裡尋找需要數據,如果第二次沒有指定或者指定別的緩存區域則沒有需要的數據,就要到數據庫中查詢了。

測試4:命名查詢

可以在映射文件中定義命名查詢,<query>元素提供了很多屬性,可以用於緩存結果,這裡,我舉一個例子吧,在Customer.hbm.xml映射文件中定義名為selectCustomer的查詢由於查詢所有Customer並啟用緩存查詢,緩存模式為默認方式(下面有說明)

<query cacheable ="true" cache-mode="normal" name="selectCustomer">
 from Customer
</query>

編寫一個方法:

[Test]
public void NamedQueryCacheTest()
{
  using (_session)
  {
    Console.WriteLine("--->第一次使用命名查詢");
    IList<Customer> customers = _session.GetNamedQuery("selectCustomer")
      .List<Customer>();
  }
  ResetSession();
  using (_session)
  {
    Console.WriteLine("--->第二次使用命名查詢");
    IList<Customer> customers = _session.GetNamedQuery("selectCustomer")
      .List<Customer>();
  }
}

測試結果:第二次直接使用二級緩存中的結果集。

NHibernate提供的查詢(HQL、條件查詢、原生SQL查詢)都類似,我在這裡就不重復舉例了,大家可以測試下。

管理NHibernate二級緩存

NHibernate二級緩存由ISessionFactory創建並由ISessionFactory自行維護。我們使用NHibernate操作數據時,ISessionFactory能夠自動同步緩存,保證緩存的有效性。但是當我們批量操作數據時,往往NHibernate不能維護緩存持久有效。ISessionFactory提供了可編程方式的緩存管理方法。

ISessionFactory提供了一系列的EvictXXX()方法可以方便的從二級緩存中刪除一個實例、刪除一個集合、一個命名緩存等操作

Evict(persistentClass):從二級緩存中刪除persistentClass類所有實例

Evict(persistentClass, id):從二級緩存中刪除指定的持久化實例

EvictEntity(entityName):從二級緩存中刪除命名實例

EvictCollection(roleName):從二級緩存中刪除集合

EvictCollection(roleName, id):從二級緩存中刪除指定的集合

EvictQueries():從二級緩存中刷新全部查詢結果集

EvictQueries(cacheRegion):從二級緩存中刷新指定查詢結果集

ISession內置緩存可以共享ISessionFactory緩存,通過指定ISession的CacheMode可以控制ISession和ISessionFactory的交互方式。ISession可以通過以下五種方式和ISessionFactory交互:

Ignore:更新數據時將二級緩存失效,其它時間不和二級緩存交互

Put:向二級緩存寫數據,但不從二級緩存讀數據

Get:從二級緩存讀數據,僅在數據更新時向二級緩存寫數據

Normal:默認方式。從二級緩存讀/寫數據

Refresh:向二級緩存寫數據,想不從二級緩存讀數據,通過在配置文件設置cache.use_minimal_puts從數據庫中讀取數據時,強制二級緩存刷新

測試5:管理NHibernate二級緩存

我們可以使用ISessionFactory提供了一系列的EvictXXX()方法從二級緩存中刪除一個實例,看看這個例子在第一次讀取持久化實例時,結果集保存在二級緩存中,使用Evict方法從二級緩存中刪除所有持久化實例,第二次查詢相同數據,二級緩存中不存在則重新從數據庫中查詢了~~

[Test]
public void SessionFactoryManageTest()
{
  ISessionFactory _sessionFactory = (new Configuration()).Configure().BuildSessionFactory();
  Console.WriteLine("第一次讀取持久化實例");
  using (ISession _session = _sessionFactory.OpenSession())
  {
    Customer customer1 = _session.Get<Customer>(1);
    Customer customer2 = _session.Get<Customer>(2);
  }
  Console.WriteLine("從二級緩存中刪除Customer類所有實例");
  _sessionFactory.Evict(typeof(Customer));
  //也可以_sessionFactory.EvictEntity("DomainModel.Entities.Customer");
  Console.WriteLine("第二次讀取持久化實例");
  using (ISession _session = _sessionFactory.OpenSession())
  {
    Customer customer1 = _session.Get<Customer>(1);
  }
}

輸出結果:

測試6:強制刷新緩存區域

我們使用ISession提供的.SetCacheMode(CacheMode.Refresh) 方法可以強制刷新緩存區域,這樣可以避免數據不一致問題~~

[Test]
public void QueryCacheTest()
{
  using (_session)
  {
    Console.WriteLine("第一次查詢某數據,顯式緩存查詢結果");
    IList<Customer> customers =
      _session.CreateQuery("from Customer c where c.CustomerId > 2")
      .SetCacheable(true)
      .SetCacheRegion("queryCache")
      .List<Customer>();
    Assert.AreEqual(11, customers.Count);
  }
  ResetSession();
  using (_session)
  {
    Console.WriteLine("第二次查詢某數據,顯式緩存查詢結果");
    Console.WriteLine("----指定特定的命名緩存區域並強制刷新緩存區域----");
    IList<Customer> customers =
      _session.CreateQuery("from Customer c where c.CustomerId > 2")
      .SetCacheable(true)
      .SetCacheRegion("queryCache")
      .SetCacheMode(CacheMode.Refresh)
      .List<Customer>();
    Assert.AreEqual(11, customers.Count);
  }
}

輸出結果:

這篇沒有什麼深入,不好意思啦~~

結語

好了,這篇就到這裡吧!揭曉了比如你修改、刪除數據時,二級緩存是什麼策略?我們如果使用查詢緩存?如何管理NHibernate二級緩存?我們合理使用緩存,可以大幅度地提高程序的性能。

出處:http://lyj.cnblogs.com

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved