用CacheDependency 實作xml檔案與緩存資料同步更新
通常,Web系統的性能瓶頸很可能是由于頻繁對資料庫或對xml等類型的資料源進行操作導緻。為了提高性能,應用程式可以将那些頻繁通路的資料存儲到緩存中。為了保證資料的正确性,則要有一定的機制來保證當緩存的資料在對應的資料源中被更改時,能夠同步更新到緩存中來。ASP.NET 提供了為緩存建立依賴項的機制來完成這一任務。其中涉及到的一個重要的類就是CacheDependency.
當緩存依賴項變更,ASP.NET将從緩存中移除該緩存。并且可以通過實作CacheItemRemovedCallback 來通知應用程式。是以應用程式就可以做出相應的處理(比如: 為該緩存項讀取新的資料)
緩存依賴項的類型有如下幾種:鍵依賴項,檔案依賴項,SQL依賴項,聚合依賴項,自定義依賴項等。其中 SQL依賴項(SqlCacheDenpendency) 的使用可以參考Petshop 4.0
本文通過實作一個Xml資料源與緩存資料同步更新的Demo來闡述檔案依賴項的用法。
Demo描述:
1) 點選連結進入詳情頁面

2) 詳情頁面(此頁面上有個兩個時間,第一個是此次進入詳情頁面的時間,第二個是從資料源中加載資料的時間。兩個時間的差異一般比較大,這是因為資料通常是從緩存讀取的)
3)當點選[UpdateCategroy.xml] 或 [UpdateProduct.xml]按鈕更新相應的xml檔案,CacheDependency觸發ASP.NET移除對應的緩存項,當緩存項被移除時,将通過CacheItemRemovedCallback 告知應用程式做出相應處理。此Demo中實作了重新從xml中讀取資料更新緩存項的功能。進而實作了xml檔案與緩存資料同步更新。
CacheManager 類
View Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Caching;
using System.Xml;
/// <summary>
/// Summary description for CacheManager
/// </summary>
public class CacheManager
{
private static bool _productsRemovedFromCache = false;
//記錄通路從xml讀取資料的相關資訊
private static Dictionary<string, string> _logs = new Dictionary<string, string>();
public static Dictionary<string, string> Logs
{
get { return _logs; }
}
private static string productxmlPath;
private static string categoryxmlPath;
//private static AggregateCacheDependency XmlFileCacheDependencyForBirds = new AggregateCacheDependency();
//private static AggregateCacheDependency XmlFileCacheDependencyForBugs = new AggregateCacheDependency();
static CacheManager()
{
productxmlPath = HttpContext.Current.Server.MapPath("App_Data/Product.xml");
categoryxmlPath = HttpContext.Current.Server.MapPath("App_Data/Category.xml");
//XmlFileCacheDependencyForBirds.Add(
// new CacheDependency(HttpContext.Current.Server.MapPath("App_Data/Product.xml")),
// new CacheDependency(HttpContext.Current.Server.MapPath("App_Data/Category.xml")));
//XmlFileCacheDependencyForBugs.Add(
// new CacheDependency(HttpContext.Current.Server.MapPath("App_Data/Product.xml")),
// new CacheDependency(HttpContext.Current.Server.MapPath("App_Data/Category.xml")));
}
//private static AggregateCacheDependency GetAggregateCacheDependency(string categoryKey)
//{
// switch (categoryKey)
// {
// case "BIRDS":
// return XmlFileCacheDependencyForBirds;
// case "BUGS":
// return XmlFileCacheDependencyForBugs;
// default:
// return null;
// }
//}
//從緩存中擷取項
public static List<Product> GetProductsByCategory(string categoryKey)
{
//不應在 ASP.NET 頁中實作回調處理程式,因為在從緩存中删除項之前該頁可能已被釋放,是以用于處理回調的方法将不可用,應該在非ASP.NET的程式集中實作回調處理程式。為了確定從緩存中删除項時處理回調的方法仍然存在,請使用該方法的靜态類。但是,靜态類的缺點是需要保證所有靜态方法都是線程安全的,是以使用lock關鍵字。
lock (typeof(CacheManager))
{
if (HttpContext.Current.Cache[categoryKey] != null)
{ //存在緩存項,傳回緩存值
return (List<Product>)HttpRuntime.Cache[categoryKey];
}
else
{ //緩存項不存在,則建立緩存項
CacheProducts(categoryKey);
return (List<Product>)HttpRuntime.Cache[categoryKey];
}
}
}
//将項以 的名稱添加到緩存中,并将該項設定為在添加到緩存中後一分鐘過期。 //并且該方法注冊 ReportRemoveCallback 方法,以便在從緩存中删除項時進行調用。
public static void CacheProducts(string categoryKey)
{
lock (typeof(CacheManager))
{
AggregateCacheDependency acd = new AggregateCacheDependency();
acd.Add(
new CacheDependency(productxmlPath),
new CacheDependency(categoryxmlPath));
HttpRuntime.Cache.Add(
categoryKey,
CreateProducts(categoryKey),
acd,
//An attempt was made to reference a CacheDependency object from more than one Cache entry.
//GetAggregateCacheDependency(categoryKey),
DateTime.MaxValue,
new TimeSpan(1, 1, 1),
System.Web.Caching.CacheItemPriority.Default,
//使用委托,在緩存删除時調用特定函數來響應。
ProductsRemovedCallback);
}
}
//建立報告,該報告時緩存項的值
private static List<Product> CreateProducts(string categoryKey)
{
List<Product> lstProduct = new List<Product>();
XmlDocument doc = new XmlDocument();
//HttpContext.Current.Server.MapPath("App_Data/Product.xml") Cache 失效後觸發此函數時,HttpContext.Current 可能為Null
doc.Load(productxmlPath);
XmlNodeList productNodeList = doc.SelectNodes(string.Format("Products/Product[@CategoryId='{0}']", categoryKey));
foreach (XmlNode productNode in productNodeList)
{
Product pro = new Product(productNode.Attributes["ProductId"].Value.ToString()
, productNode.Attributes["Name"].Value.ToString()
, productNode.Attributes["Descn"].Value.ToString()
, productNode.Attributes["Image"].Value.ToString()
, productNode.Attributes["CategoryId"].Value.ToString());
lstProduct.Add(pro);
}
_logs.Remove(categoryKey);
_logs.Add(categoryKey, string.Format("{1} (Access xml file to get product {0}'s data)", categoryKey, DateTime.Now.ToString()));
return lstProduct;
}
/// <summary>
/// 當從緩存中删除項時調用該方法
/// </summary>
/// <param name="key">CacheKey</param>
/// <param name="value">Cache Data</param>
/// <param name="removedReason">Removed/Expired/Underused/DependencyChanged</param>
public static void ProductsRemovedCallback(String key, object value,
CacheItemRemovedReason removedReason)
{
_productsRemovedFromCache = true;
CacheProducts(key);
}
}
複制代碼
Demo代碼下載下傳
參考資料:
http://www.cnblogs.com/wayfarer/archive/2006/11/01/547060.html