NHibernate初学者指南(10):一级和二级缓存
一級緩存
為了獲得更好的性能,NHibernate智能地緩存數(shù)據(jù)。NHibernate有不同的緩存機制起作用,最重要的就是一級緩存。每個session對象維持一個一級緩存,session對象創(chuàng)建時緩存創(chuàng)建,session對象釋放時緩存銷毀。
緩存只不過是一個哈希表。哈希表根據(jù)唯一鍵存儲值,值可以根據(jù)唯一鍵檢索。
一個實體由它的ID唯一標識,如果兩個實體類型相同,ID也相等,那么這兩個實體是相等的。NHibernate要求兩個相同類型的對象不能有相同的ID。原因是,如果允許系統(tǒng)有相同ID的兩個實例,那么就會將系統(tǒng)置于不一致的狀態(tài)中。有了這個條件,NHibernate就可以執(zhí)行下面的操作了:
NHibernate session對象從數(shù)據(jù)庫中加載指定ID的實體,然后放到一級緩存中,訪問該實體的鍵是它的ID值。當系統(tǒng)再次從數(shù)據(jù)庫中加載同一個實體時,session對象首先檢查它的緩存,如果實體已經(jīng)存在于緩存中,NHibernate就返回緩存的實例。只有實體不在緩存時,NHibernate session對象才從數(shù)據(jù)庫中加載實體??聪旅娴倪^程:
- 程序請求session ID為1的product
- session問一級緩存:“有ID為1的product嗎?”
- 一級緩存回答說:“沒有”
- session就從數(shù)據(jù)庫中加載ID為1的product
- session將product放入一級緩存,鍵為product的ID值
- session返回給程序product實例
- 程序執(zhí)行更多的操作
- 程序再次請求session ID為1的product
- session問一級緩存:“有ID為1的product嗎”
- 一級緩存回答說:“有”
- session就使用ID作為鍵從緩存中加載ID為1的product,并返回給程序
我們使用下面的代碼從數(shù)據(jù)庫中加載實體并隱式的使NHibernate session將它存儲到一級緩存:
var product = sesson.Get<Product>(1);之后的Get操作不會引起NHibernate查詢數(shù)據(jù)庫而是從一級緩存中檢索對象。
清除緩存
我們使用下面的語句請求session從一級緩存中移除一個實體:
session.Evict(product);如果想完全的清除緩存,可以使用下面的代碼:
session.Clear();上述語句應(yīng)該僅在特殊情況下使用,因為,如果使用不當會導致顯著的性能下降。建議只在寫測試代碼時使用這些操作。
刷新緩存中的實體
如果想刷新一級緩存中的單個實體,那么可以使用下面的語句:
session.Refresh(product);上面的代碼重新從數(shù)據(jù)庫中加載product實體的狀態(tài),這在session打開的同時數(shù)據(jù)庫里的實體被其他程序更改的情況下非常有意義。
二級緩存
我們已經(jīng)看到NHibernate提供了非常有效的方式緩存數(shù)據(jù)??上?#xff0c;一級緩存綁定到session對象,也就是說每次session被釋放,所有的緩存數(shù)據(jù)就會丟失。二級緩存定義在session工廠級別的,只要session工廠沒有被釋放緩存就一直存在。一旦實體加載,二級緩存就被激活,實體對所有的session(同session工廠的)都可用。這樣,只要實體在二級緩存中,NHibernate就不會從數(shù)據(jù)庫加載實體,直到它從緩存中移除。
啟動二級緩存,我們就要定義使用哪個緩存提供程序。二級緩存有各種實現(xiàn)。我們的例子中使用基于哈希表的緩存,它包含在核心的NHibernate程序集中。請注意,不應(yīng)該在生產(chǎn)級的代碼中使用這種緩存提供程序,僅僅用在測試中。參看后面的“二級緩存的實現(xiàn)”部分,選擇哪個實現(xiàn)最適合你;然而,如果你改變了緩存提供程序,你不用修改你的代碼。
使用下面的代碼只會引發(fā)NHibernate訪問一次數(shù)據(jù)庫檢索ID為1的product,即使我們使用兩個不同的session實例:
using (var session1 = sessionFactory.OpenSession()) { var product = session1.Get<Product>(1); } using (var session2 = sessionFactory.OpenSession()) { var product = session2.Get<Product>(1); }第二個Get操作會從二級緩存中獲取product實體。然而要注意的是,如果沒有啟動二級緩存,上面的代碼會訪問兩次數(shù)據(jù)庫。
另外,啟動二級緩存,必須相應(yīng)的配置NHibernate。配置的詳細內(nèi)容會在后面介紹。我們還必須映射實體為可緩存的。如果使用fluent映射映射實體,那么添加到映射的必要語句是:
Cache.ReadWrite();只有顯示配置的實體才會緩存在二級緩存中。
緩存區(qū)域
如果不使用緩存區(qū)域,那么二級緩存只能整體清除。如果需要清除二級緩存的一部分,就得使用緩存區(qū)域。緩存區(qū)域根據(jù)它們的名字區(qū)分。我們可以將任何數(shù)量的不同查詢放在命名的緩存區(qū)域中。清除一個緩存區(qū)域的命令如下:
sessionFactory.EvictQueries("My Region");當前使用的sessionFactory是session工廠的實例,My Region是緩存區(qū)域的名字。
二級緩存的實現(xiàn)
所有的二級緩存提供程序都是NHibernate contributions項目的一部分。下面列表給出了一些支持的提供程序的簡短描述。
- SysCache:使用System.Web.Caching.Cache作為緩存提供程序。也就是說可以依靠ASP.NET的緩存功能來理解它如何工作。
- SysCache2:和NHibernate.Caches.SysCache一樣,使用ASP.NET緩存。這個提供程序也支持SQL基于依賴過期,意思是當數(shù)據(jù)庫里的相關(guān)數(shù)據(jù)發(fā)生改變不可能自動地配置某些緩存區(qū)域。
- Velocity:它是Microsoft Windows Server App Fabric的一部分,是一組構(gòu)建、擴展和管理基于IIS的web應(yīng)用程序的綜合服務(wù)。
- Prevalence:使用Bamboo.Prevalence作為緩存提供程序。Bamboo.Prevalence是由Klaus Wuestefeld在Prevayler中提出的對象流行概念的.NET實現(xiàn)。Bamboo.Prevalence提供針對CLR的確定性系統(tǒng)的透明對象持久化。它為智能客戶端應(yīng)用程序提供持久化的緩存。
- MemCache:Memcached.Memcahed是一個高性能,分布式內(nèi)存對象緩存系統(tǒng),但是旨在通過減輕數(shù)據(jù)庫負載加速動態(tài)web應(yīng)用程序。根本上說,就是一個分布式的哈希表。
實例—使用二級緩存
在這個例子中,我們使用NHibernate的二級緩存實現(xiàn)一個非常簡單的例子。我們在例子中使用哈希表緩存提供程序,但是在生產(chǎn)級代碼中不要使用這個提供程序!
1. 在SSMS中創(chuàng)建一個數(shù)據(jù)庫:SecondLevelCacheSample。
2. 打開Visual Studio,創(chuàng)建一個Console Application:SecondLevelCacheSample。
3. 添加對NHibernate.dll,FluentNHibernate.dll和NHibernate.ByteCode.Castle.dll程序集的引用。
4. 在項目中創(chuàng)建Domain文件夾。
5. 在Domain文件夾中創(chuàng)建一個類文件Product.cs,添加如下代碼:
public class Product {public virtual int Id { get; set; }public virtual string Name { get; set; }public virtual decimal UnitPrice { get; set; }public virtual int ReorderLevel { get; set; }public virtual bool Discontinued { get; set; } }6. 在Domain文件夾中添加一個ProductMap.cs類文件用來映射Product實體,代碼如下:
public class ProductMap : ClassMap<Product> {public ProductMap(){Cache.ReadWrite();Id(x => x.Id).GeneratedBy.HiLo("1000");Map(x => x.Name);Map(x => x.UnitPrice);Map(x => x.ReorderLevel);Map(x => x.Discontinued);} }注意在映射中添加了Cache.ReadWrite()語句用來告訴NHibernate為Product實體使用二級緩存。
7. 在Program類中添加一個ISessionFactory類型的靜態(tài)字段,如下:
private static ISessionFactory sessionFactory;8. 在Program類中添加一個靜態(tài)方法:ConfigureSystem。這個方法包含配置NHibernate的一般代碼和二級緩存的代碼。如下面的代碼所示:
private static void ConfigureSystem() {const string connString ="server=.;database=SecondLevelCacheSample;" +"user id=sa;password=sasa;";var configuration = Fluently.Configure().Database(MsSqlConfiguration.MsSql2008.ConnectionString(connString).ShowSql).Mappings(m => m.FluentMappings.AddFromAssemblyOf<Product>()).BuildConfiguration();configuration.Properties["cache.provider_class"] = "NHibernate.Cache.HashtableCacheProvider";configuration.Properties["cache.use_second_level_cache"] = "true";var exporter = new SchemaExport(configuration);exporter.Execute(true, true, false);sessionFactory = configuration.BuildSessionFactory(); }配置二級緩存的代碼中,第一個是告訴NHibernate使用哪個二級緩存提供程序。它是一個鍵值對。值是實現(xiàn)二級緩存提供程序類的全路徑。在我們的例子中不需要定義程序集,因為該提供程序在NHibernate程序集內(nèi)。第二個是啟用或禁止二級緩存的使用。注意,從技術(shù)上來說,第二個配置不需要,因為它的默認值是true。
9. 在Program類中,創(chuàng)建一個TestLoadEntity的靜態(tài)方法,代碼如下:
private static void TestLoadEntity() {int productId;var product = new Product{Name = "Apple",UnitPrice = 1.55m,ReorderLevel = 100,Discontinued = false};using (var session = sessionFactory.OpenSession()){using (var tx = session.BeginTransaction()){productId = (int)session.Save(product);tx.Commit();}}using (var session1 = sessionFactory.OpenSession()){var product1 = session1.Get<Product>(productId);}using (var session2 = sessionFactory.OpenSession()){var product2 = session2.Get<Product>(productId);} }10. 在Main方法中調(diào)用ConfigureSystem和TestLoadEntity方法:
static void Main(string[] args) {ConfigureSystem();TestLoadEntity();Console.Write("\r\nHit enter to exit:");Console.ReadLine(); }11. 運行程序,驗證沒有select語句生成。這說明二級緩存起作用了。
12. 現(xiàn)在改變cache.use_second_level_cache設(shè)置為false,再次運行程序。這次,有兩個select語句發(fā)送到數(shù)據(jù)庫,如下圖所示:
很明顯,除了insert語句外,還有兩個select語句:每個session對象一個,用來加載product實體。
在這個例子中,我們學會了如何配置程序以便NHibernate使用二級緩存,也學會了如何配置實體映射以便它們可以被緩存到二級緩存中。
轉(zhuǎn)載于:https://www.cnblogs.com/nianming/archive/2011/11/17/2253201.html
總結(jié)
以上是生活随笔為你收集整理的NHibernate初学者指南(10):一级和二级缓存的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: KL距离简介
- 下一篇: ubuntu软件(查看文件差异)