本節內容
引入
使用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