原文:https://www.cnblogs.com/kissdodog/archive/2013/05/07/3064895.html
Cache類,是一個用於緩存常用信息的類。HttpRuntime.Cache以及HttpContext.Current.Cache都是該類的實例。 一、屬性
二、方法
三、靜態字段
先來看基本的示例: index.aspx.cs頁面代碼: namespace WebApplication1 { public partial class _Default : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { Person p = new Person(); p.Id = 1; p.Name = "諸葛亮"; Cache cache = HttpRuntime.Cache; cache.Insert("AA",p); cache.Insert("BB","字符串"); Response.Write(cache.Get("BB").ToString()); //輸出 字符串 Person p2 = cache["AA"] as Person; Response.Write(p2.Id + " : " + p2.Name); //輸出 1 : 諸葛亮 Response.Write(cache.EffectivePrivateBytesLimit); //-1 這是一個只讀屬性,那就沒什么好說了,只能輸出來看看了,但是-1是什么意思呢?無限嗎 Response.Write(cache.EffectivePercentagePhysicalMemoryLimit); //98 開始移除項之前可以使用到98% Response.Write(cache.Count); //輸出 3 Response.Write(cache["BB"]); //輸出 字符串 支持索引器式的讀取 cache.Remove("BB"); //從cache中移除一項 Response.Write("~~~" + cache["BB"] + "~~~"); //移除了輸出 null,但程序不報錯 foreach (var obj in cache) { Response.Write(obj.GetType() + "<br/>"); //輸出不知道什么鳥東西 } } } public class Person { public int Id { get; set; } public string Name { get; set; } } } 四、文件緩存依賴當被依賴的文件更改時,緩存會立即被清空: index.aspx.cs代碼: public partial class _Default : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { Cache cache = HttpContext.Current.Cache; //文件緩存依賴 cache.Insert("CC", "依賴項測試", new CacheDependency(@"D:\123.txt")); //這時候在about.aspx頁面添加一行代碼,當更改一下D:123.txt時,cache["cc"]會立即被清空 } } about.aspx.cs代碼: public partial class About : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { //直接打開本頁面,輸出緩存依賴項測試 //當更改D:\123.txt之后,在刷新,輸出空,表明該Cache是依賴於D:\123.txt的 Response.Write(HttpContext.Current.Cache["CC"]); } } 五、NoSlidingExpiration 絕對過期時間NoSlidingExpiration 絕對過期時間,當超過設定時間,立即移除。 下面來看下絕對過期時間的示例,index.aspx.cs: public partial class _Default : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { Cache cache = HttpContext.Current.Cache; //30秒后就到期,立即移除,沒商量 cache.Insert("DD", "絕對過期測試", null, DateTime.Now.AddSeconds(5), System.Web.Caching.Cache.NoSlidingExpiration); } } about.aspx.cs: public partial class About : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { //先打開index.aspx添加到緩存 然后立即打開本頁面,輸出 絕對過期測試 //持續刷新5秒后,不會再輸出 絕對過期測試 Response.Write(HttpContext.Current.Cache["DD"]); } } 六、NoAbsoluteExpiration 滑動過期時間NoAbsoluteExpiration 當超過設定時間沒再使用時,才移除緩存 滑動過期測試,index.aspx.cs: public partial class _Default : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { Cache cache = HttpContext.Current.Cache; //彈性過期時間,當緩存沒使用10秒就過期 cache.Insert("DD", "滑動過期測試", null, System.Web.Caching.Cache.NoAbsoluteExpiration,TimeSpan.FromSeconds(10)); } } about.aspx.cs: public partial class About : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { //直接打開本頁面,輸出彈性過期測試 //如果一直不停地刷新,都會繼續輸出,但是當超過10秒后再刷新,不會再輸出 滑動緩存測試 Response.Write(HttpContext.Current.Cache["DD"]); } } 注意 當設置絕對到期時間時,請使用 DateTime 結構。當設置彈性過期時間時,請使用 TimeSpan 結構。另外,如果您創建的彈性過期時間小於零或大於一年,則將引發 ArgumentOutOfRangeException 類。 七、緩存的優先級設置CacheItemPriority枚舉 設置緩存的優先級 public partial class _Default : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { Cache cache = HttpContext.Current.Cache; //文件權重級別 cache.Add("MyData", "緩存重要級別", null, Cache.NoAbsoluteExpiration, TimeSpan.FromSeconds(30), CacheItemPriority.High, null); } } 該枚舉一共有六級: //在服務器釋放系統內存時,具有該優先級級別的緩存項最有可能被從緩存刪除。 Low = 1,//在服務器釋放系統內存時,具有該優先級級別的緩存項比分配了 System.Web.Caching.CacheItemPriority.Normal //優先級的項更有可能被從緩存刪除。 BelowNormal = 2,//在服務器釋放系統內存時,具有該優先級級別的緩存項很有可能被從緩存刪除,其被刪除的可能性僅次於具有 System.Web.Caching.CacheItemPriority.Low Normal = 3,//緩存項優先級的默認值為 System.Web.Caching.CacheItemPriority.Normal。 Default = 3,//在服務器釋放系統內存時,具有該優先級級別的緩存項被刪除的可能性比分配了 System.Web.Caching.CacheItemPriority.Normal //優先級的項要小。 AboveNormal = 4,//在服務器釋放系統內存時,具有該優先級級別的緩存項最不可能被從緩存刪除。 High = 5,//在服務器釋放系統內存時,具有該優先級級別的緩存項將不會被自動從緩存刪除。但是,具有該優先級級別的項會根據項的絕對到期時間或可調整到期時間與其他項一起被移除 NotRemovable = 6,
八、當緩存被移除時,通知程序這時就要用到Add的最后一個參數,委托了: index.aspx.cs代碼如下: public partial class _Default : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { Cache cache = HttpRuntime.Cache; //文件權重級別 cache.Add("MyData", "緩沖移除通知", null, DateTime.Now.AddSeconds(10) ,Cache.NoSlidingExpiration,CacheItemPriority.Low, Show); } public void Show(string key, object value, CacheItemRemovedReason reason) { Cache cache = HttpRuntime.Cache; Cache.Insert("MyData", "緩存被清空啦!緩存被清空啦!緩存被清空啦!緩存被清空啦!緩存被清空啦!緩存被清空啦!緩存被清空啦!"); } } about.aspx.cs代碼如下: public partial class About : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { Response.Write(HttpRuntime.Cache["MyData"]); } } 此處實現的效果時:第一次打開index.aspx(讓程序加入數據到緩存),然后打開about.aspx顯示出“緩存移除通知”,10秒后再刷新,顯示 “緩存被清空啦!緩存被清空啦!緩存被清空啦!緩存被清空啦!緩存被清空啦!緩存被清空啦!緩存被清空啦!” 經測試,以上程序的Cache最好還是用HttpRuntime的,否則沒有請求時HttpContext會報,“未將對象引用設置到對象的實例”。 這就是被清空時會自動調用委托程序進行處理,你可以再次將數據添加進入緩存,或者記錄到日志等等一系列操作。 九、數據庫依賴緩存1、配置的方式(sqlserver2000) SqlDependency第一個構造函數。 首先一個WebForm的Web.Config中的配置文件修改如下: <connectionStrings> <add name="ApplicationServices" connectionString="Server=KISSDODOG-PC;Database=Nx;uid=sa;pwd=123;" providerName="System.Data.SqlClient" /> </connectionStrings> <system.web> <compilation debug="true" targetFramework="4.0" /> <caching> <sqlCacheDependency enabled="true" pollTime="1000"> //此行配置的意思是,開啟數據庫緩存,輪詢時間為1秒,這是為了能夠快速看到更改效果 <databases> <add connectionStringName="ApplicationServices" name="con"/> </databases> </sqlCacheDependency> </caching> </system.web> 修改Global.asax.cs文件代碼如下: void Application_Start(object sender, EventArgs e) { string connString = System.Web.Configuration.WebConfigurationManager.ConnectionStrings["ApplicationServices"].ConnectionString; SqlCacheDependencyAdmin.EnableNotifications(connectionString); //啟動數據庫的數據緩存依賴功能 Index.aspx.cs文件代碼如下: protected void Page_Load(object sender, EventArgs e) { SqlCacheDependency dependency = new SqlCacheDependency("con", "Record"); // 新增或修改一條緩存記錄 HttpRuntime.Cache.Insert("MyData", "數據庫緩存測試", dependency); } About.aspx.cs文件代碼如下: protected void Page_Load(object sender, EventArgs e) { Response.Write(HttpRuntime.Cache["MyData"]); } 次數實現的效果時,打開Index.aspx.cs文件將數據添加到緩存后,然后打開about.asox,頁面輸出"數據庫緩存測試",這時候更改一下數據庫的Record表,再刷新about.aspx頁面,上一次輸出的內容沒有了。 System.Data.SqlClient.SqlDependency.Start(connString); System.Data.SqlClient.SqlDependency.Stop(connString); 這兩行代碼不一定要放在Global.asax.cs里面,在代碼執行之前和執行之后就OK了。 注意,在這個例子當中,數據庫要開啟Service Broker 檢測是否已經啟用Service Broker Select DATABASEpRoPERTYEX('數據庫名稱','IsBrokerEnabled') -- 1 表示已經啟用 0 表示沒有啟用 啟用Servicce Broker ALTER DATABASE NX SET ENABLE_BROKER; 如果啟動時,一直顯示正在執行查詢,那么用一下這條語句 ALTER DATABASE NX SET NEW_BROKER WITH ROLLBACK IMMEDIATE; ALTER DATABASE NX SET ENABLE_BROKER; 2、編程的方式(sqlserver2008),第二個構造函數SqlDependency(sqlcommand sqlcom) index.aspx.cs文件代碼如下: protected void Page_Load(object sender, EventArgs e) { SqlCacheDependency dependency; SqlConnection conn = new SqlConnection(@"Server=KISSDODOG-PC;Database=Nx;uid=sa;pwd=123;"); using (conn) { string sql = "select name from dbo.record"; SqlCommand cmd = new SqlCommand(sql, conn); dependency = new SqlCacheDependency(cmd); SqlDataAdapter adapter = new SqlDataAdapter(cmd); //這里要特別注意,你的cmd一定要執行過,或者說Execute過,真正從數據庫里面取出過數據 DataSet ds = new DataSet(); adapter.Fill(ds); //這里才是cmd真正執行的地方,注意真正執行要在綁定dependency之后 } Response.Write("開始!"); Cache.Insert("MyData", "數據庫依賴測試", dependency); Response.Write("完成!"); } about.aspx.cs代碼文件如下: public partial class About : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { if (HttpRuntime.Cache["MyData"] != null) { Response.Write(HttpRuntime.Cache["MyData"]); } else { Response.Write("緩存已不存在!"); } } } 實現的效果一樣是,打開index.aspx文件,再打開about.aspx文件,頁面輸出"緩存測試結果",當更改表record之后,再刷新about.aspx頁面,緩存被清空。 再來一個例子,上次又是頁面啥的,這次用十幾行代碼說明,這個東東實現的要點: static void Main(string[] args) { Cache cache = HttpRuntime.Cache; System.Data.SqlClient.SqlDependency.Start(@"Server=KISSDODOG-PC;Database=Nx;uid=sa;pwd=123;"); // 創建緩存依賴 SqlConnection conn = new SqlConnection(@"Server=KISSDODOG-PC;Database=Nx;uid=sa;pwd=123;"); SqlCommand command = new SqlCommand("select Id,name from dbo.Record", conn); SqlCacheDependency dependency = new SqlCacheDependency(command); //注意,創建的command與SqlCacheDependency綁定要在command執行之前 SqlDataAdapter adapter = new SqlDataAdapter(command); DataSet ds = new DataSet(); adapter.Fill(ds); //這里要特別注意,Fill才是真正執行 cache.Insert("DD", "數據庫依賴測試", dependency); Console.WriteLine(cache["DD"]); Thread.Sleep(20000); //暫停20秒給你更改一下數據庫 if (cache["DD"] == null) { Console.WriteLine("數據庫已經修改過了!"); } Console.ReadKey(); System.Data.SqlClient.SqlDependency.Stop(@"Server=KISSDODOG-PC;Database=Nx;uid=sa;pwd=123;"); } 在途中,我會隨便修改一下Record表,輸出結果如下: 再來一次數據庫緩存依賴,回調函數的例子: public class Program { static void Main(string[] args) { Cache cache = HttpRuntime.Cache; System.Data.SqlClient.SqlDependency.Start(@"Server=KISSDODOG-PC;Database=Nx;uid=sa;pwd=123;"); // 創建緩存依賴 SqlConnection conn = new SqlConnection(@"Server=KISSDODOG-PC;Database=Nx;uid=sa;pwd=123;"); SqlCommand command = new SqlCommand("select Id,name from dbo.Record", conn); SqlCacheDependency dependency = new SqlCacheDependency(command); //注意,創建的command與SqlCacheDependency綁定要在command執行之前 SqlDataAdapter adapter = new SqlDataAdapter(command); DataSet ds = new DataSet(); adapter.Fill(ds); //這里要特別注意,Fill才是真正執行 CacheItemRemovedCallback callback = new CacheItemRemovedCallback(RemovedCallback); cache.Insert("DD", "數據庫依賴測試", dependency, DateTime.Now.AddDays(1), TimeSpan.Zero, CacheItemPriority.Default, callback); Console.WriteLine(cache["DD"]); Thread.Sleep(15000); //暫停15秒給你更改一下數據庫 if (cache["DD"] == null) { Console.WriteLine("數據庫已經修改過了!"); } Console.ReadKey(); System.Data.SqlClient.SqlDependency.Stop(@"Server=KISSDODOG-PC;Database=Nx;uid=sa;pwd=123;"); } public static void RemovedCallback(string key, object value, CacheItemRemovedReason reason) { Console.WriteLine("緩存被移除!"); Console.WriteLine(reason.ToString()); } } 輸出結果如下: 這里要補充幾點:當設置為絕對過期時,后面那個TimeSpan參數要設為TimeSpan.Zero。另外,重載中還有一個方法之前在緩存移除前執行回調函數的,而剛剛那個是緩存數據被移除之后執行的。 CacheItemUpdateCallback 緩存數據移除之前調用; CacheItemRemoceCallback 緩存數據移除之后調用; 再來寫一個: public class Program { static void Main(string[] args) { Cache cache = HttpRuntime.Cache; System.Data.SqlClient.SqlDependency.Start(@"Server=KISSDODOG-PC;Database=Nx;uid=sa;pwd=123;"); // 創建緩存依賴 SqlConnection conn = new SqlConnection(@"Server=KISSDODOG-PC;Database=Nx;uid=sa;pwd=123;"); SqlCommand command = new SqlCommand("select Id,name from dbo.Record", conn); SqlCacheDependency dependency = new SqlCacheDependency(command); //注意,創建的command與SqlCacheDependency綁定要在command執行之前 SqlDataAdapter adapter = new SqlDataAdapter(command); DataSet ds = new DataSet(); adapter.Fill(ds); //這里要特別注意,Fill才是真正執行 CacheItemUpdateCallback callback = new CacheItemUpdateCallback(RemovedCallback); cache.Insert("DD", "數據庫依賴測試", dependency, DateTime.Now.AddDays(1), TimeSpan.Zero, callback); Console.WriteLine(cache["DD"]); Thread.Sleep(15000); //暫停15秒給你更改一下數據庫 if (cache["DD"] == null) { Console.WriteLine("數據庫已經修改過了!"); } Console.ReadKey(); System.Data.SqlClient.SqlDependency.Stop(@"Server=KISSDODOG-PC;Database=Nx;uid=sa;pwd=123;"); } public static void RemovedCallback(string key, CacheItemUpdateReason reason, out object expensiveObject, out CacheDependency dependency, out DateTime absoluteExpiration, out TimeSpan slidingExpiration) { // key:要從緩存中移除的項的標識符。 // reason:要從緩存中移除項的原因。 // expensiveObject:此方法返回時,包含含有更新的緩存項對象。 // dependency:此方法返回時,包含定義項對象和文件、緩存鍵、文件或緩存鍵的數組或另一個 System.Web.Caching.CacheDependency 對象之間的依賴項的對象。 // absoluteExpiration:此方法返回時,包含對象的到期時間。 // slidingExpiration:此方法返回時,包含對象的上次訪問時間和對象的到期時間之間的時間間隔。 expensiveObject = null; dependency = null; absoluteExpiration = DateTime.Now; slidingExpiration = TimeSpan.Zero; Console.WriteLine("緩存馬上被移除!"); //但是現在還有沒有呢?輸出試試 Console.WriteLine(HttpRuntime.Cache["DD"]); Console.WriteLine(reason.ToString()); } } 輸出結果為: 看到,在Update這個委托執行時,緩存還是存在的。 注意:那個SQL語句還是比較嚴格的,主要要符合以下要求 a). 必須設置完全限定名稱的數據表。即表名前面需要加所有者,如dbo.test。 b). 必須明確設置所訪問數據庫列名稱,不能使用“*”。 c). 必須保證不是聚合函數。如COUNT、MAX等。
很明顯,SQL SERVER 2005的緩存機制更加高效。另外,SqlCacheDependency類還特別結合SQL SERVER 2005 進行了優化: a). 使用SQL SERVER 2005 時,SqlCacheDependency類支持與System.Data.SqlClient.SqlDependency類進行集成。應用程序可創建SqlDependency對象,並通過OnChanged事件處理程序接受通知進行注冊。這樣,應用程序不僅可以使用Sql server 2005的查詢通知機制來監測使用SQL查詢結果無效的數據更改,並將緩存對象從緩存中移除,而且還可以輕松獲取數據更改通知,以便刷新緩存。(從這里可以看出,當觸發onRemoveCallback委托的時候,數據已經從緩存里面刪除了,這樣一來可以手動在委托里面添加緩存,或者干脆設置成null,讓他下次調用的時候再緩存。) b). 不僅向應用程序添加緩存依賴項,還可以與@OutputCache指令一起使用,以生成依賴於SqlServer數據庫表的輸出緩存的頁面或用戶控件。對於用戶控件,@OutputCache指令不支持使用SQL SERVER 2005 的查詢通知(即onRemoveCallback委托)。 十、組合依賴緩存 當依賴的內容為多個Dependency時,可以通過AggregateCacheDependency創建依賴的組合,以便在任何一個依賴項發生變化時,使緩存項失效。 組合依賴緩存示例: //創建緩存依賴 System.Web.Caching.SqlCacheDependency product = new System.Web.Caching.SqlCacheDependency("northwindcache","products"); System.Web.Caching.SqlCacheDependency category = new System.Web.Caching.SqlCacheDependency("northwindcache","products") //多個緩存依賴組合成一個依賴對象使用 System.Web.Caching.AggregateCacheDependency acd = new System.Web.Caching.AggregateCacheDependency(); acd.Add(product,category);
十一、System.Web.Caching.Cache Insert和Add方法的區別Add方法 object Add(string key, object value, CacheDependency dependencies, DateTime absoluteExpiration, TimeSpan slidingExpiration, CacheItemPriority priority, CacheItemRemovedCallback onRemoveCallback); Insert方法 void Insert(string key, object value); //永不過期 void Insert(string key, object value, CacheDependency dependencies); //依賴 void Insert(string key, object value, CacheDependency dependencies, DateTime absoluteExpiration, TimeSpan slidingExpiration);//絕對時間過期: void Insert(string key, object value, CacheDependency dependencies, DateTime absoluteExpiration, TimeSpan slidingExpiration, CacheItemUpdateCallback onUpdateCallback); //依賴+回調 void Insert(string key, object value, CacheDependency dependencies, DateTime absoluteExpiration, TimeSpan slidingExpiration, CacheItemPriority priority, CacheItemRemovedCallback onRemoveCallback); //依賴+優先級+回調 比較、區別 a). Insert方法支持5種重載,使用靈活,而Add方法必須提供7個參數; b). Add方法可以返回緩存項的數據對象,Insert 返回Void; c). 添加重復緩存情況下(Key已存在),Insert會替換該項,而Add方法則不執行任何操作,並返回原來保存的object對象(Update 2014-03-18)。 過期策略 a). 永不過期 b). 絕對時間過期 DateTime.Now.AddSeconds(10)表示緩存在10秒后過期,TimeSpan.Zero表示不使用平滑過期策略。 例:Cache.Insert("Data", ds,null, DateTime.Now.AddSeconds(10), TimeSpan.Zero); c). 變化時間過期(平滑過期) DateTime.MaxValue表示不使用絕對時間過期策略,TimeSpan.FromSeconds(10)表示緩存連續10秒沒有訪問就過期。 例:Cache.Insert("Data", ds, null, DateTime.MaxValue, TimeSpan.FromSeconds(10)); 十二、清空緩存清空緩存主要通過Remove()方法,但是只能通過傳入一個Key,清空一個。 GetEnumerator()方法用於獲取所有緩存項。MoveNext()用於將位置移動到下一個緩存項。 如果想清空所有緩存,由於Cache類沒有提供RemoveAll()方法,所以可以通過以下方式實現: IDictionaryEnumerator DicCache = HttpRuntime.Cache.GetEnumerator(); int count = HttpRuntime.Cache.Count; for (int i = 0; i < count; i++) { DicCache.MoveNext(); HttpRuntime.Cache.Remove(DicCache.Entry.Key.ToString()); } 十三、緩存依賴總結緩存依賴主要有如下技術點 Dependency依賴:.Net中支持兩種依賴:CacheDependency和SqlDependency(兩者都是Dependency的子類)。從.Net2.0開始,CacheDependency不再是密封的,而是可以繼承的。 過期時間:過期時間分絕對過期時間和滑動過期時間兩種。 刪除通知:.Net提供了一個機制,當被緩存的數據從內存中移除的時候,可以提供一個通知機制,來回調用戶定義的方法,方法必須符合CacheItemRemoveCallback委托的定義。該委托定義如下: public delegate void CacheItemRemoveCallback(string key,Object value,CacheItemRemovedReason reason) 其中,CacheItemRemoveReason為緩存項被移除的原因。CacheItemRemovedReason是一個枚舉類型,定義了如下原因:
注意:
PS: 1、 CacheDependency是AggregateCacheDependency和SqlCacheDependency的父類。主要用於在應用程序數據緩存對象與文件、緩存鍵、文件或緩存鍵的數組或另外一個CacheDependency對象之間建立依賴關系。CacheDependency監視依賴關系比便在任何對象更改時自動移除緩存對象。CacheDependency可以監測一組(到文件或目錄的)文件路徑的更改情況。 2、 AggregateCacheDependency主要用於實現聚合緩存依賴。如一筆數據同時對兩個表進行緩存依賴,一旦其中任何一個表數據更改緩存將失效。 3、 SqlCacheDependency將應用程序數據緩存對象、頁面輸出緩存、數據源控件等與指定SQL Server數據庫表或Sql Server 2005 查詢結果之間建立緩存依賴關系,在表發生更改(Sql Server 2005 行級別更改)時,自動從緩存中刪除和重新添加與該表關聯的緩存對象。一般而言:
有以下幾條緩存數據的規則。: 你應該認真分析你的程序。根據實際情況來看哪里該用,哪里不該用。如:Cache用得過多也會增大服務器的壓力。整頁輸出緩存,又會影響數據的更新。 如果真的需要緩存很大量的數據,可以考慮靜態技術。 CacheDependency還支持【嵌套】,即:CacheDependency的構造函數中支持傳入其它的CacheDependency實例,這樣可以構成一種非常復雜的樹狀依賴關系。 |