缓存的方式有很多中:
Output Caching 输出缓存
Fragment Caching
Data Caching
SQL Cache
Cache Configuration 配置缓存
一、Output Caching输出缓存有两种方法,一种是基于底层的API技术,一种是基于高层的@OutputCaching。
一旦Output Caching被定制过,网页第一次被访问过的时候就回生成cache,直至请求过期为止。
不说那么多了,先看下petshop中是怎么使用页面缓存的把,嗯,错了,petshop是没使用这种缓存的。那么Output Caching缓存该怎么做呢?
<%@ OutputCache Duration="60" VaryByParam="*" %>
其中Duration是对缓存的页面设置过期时间。VaryByParam应该是指定参数吧,*号表示对所以内容都缓存吧。
她有使用Fragment Caching,即片段缓存。
但其实质跟页面缓存差不多。
petshop的片段缓存不是单纯的缓存,他还用到了SQL Cache,这是.net的新特性,这个缓存对象可以很好解决数据库变化对已缓存页面的改变(这里不多说)。
就拿ProductsControl.ascx这个控件来说把:
在前台导入页面设置:<%@ OutputCache Duration="100000" VaryByParam="page;categoryId" %>
为何VaryByParam的值是page和categoryId呢?categoryId是根据类别来判断要显示的product。但是page我就不明白了(待续)。
下面是ProductsControl.ascx.cs的代码:
public partial class ProductsControl : System.Web.UI.UserControl { /// <summary> /// Rebind control /// </summary> protected void PageChanged(object sender, DataGridPageChangedEventArgs e) { //reset index productsList.CurrentPageIndex = e.NewPageIndex; //get category id string categoryKey = Request.QueryString["categoryId"]; //bind data Product product = new Product(); productsList.DataSource = product.GetProductsByCategory(categoryKey); productsList.DataBind(); } /// <summary> /// Add cache dependency /// </summary> protected void Page_Load(object sender, EventArgs e) { this.CachePolicy.Dependency = DependencyFacade.GetProductDependency(); } }
其中对数据的绑定是没有什么变化,最重要的要看page_Load的:
this.CachePolicy.Dependency = DependencyFacade.GetProductDependency();
增加了这句就可以对数据库的表进行实时增删改监控(用词不当吧)吧。
但是petshop还为我们展示了另外一种缓存方法,这种方法要叫什么呢?我查了下应该就是传说中的Date Cache(数据缓存)吧:
且看他们是怎么来做滴(我就拿CategoryDataProxy.cs来说明吧),下面就是这个类的一个方法了:
public static IList<CategoryInfo> GetCategories() { Category cat = new Category(); if (!enableCaching) return cat.GetCategories(); string key = "category_all"; IList<CategoryInfo> data = (IList<CategoryInfo>)HttpRuntime.Cache[key]; // Check if the data exists in the data cache if (data == null) { // If the data is not in the cache then fetch the data from the business logic tier data = cat.GetCategories(); // Create a AggregateCacheDependency object from the factory AggregateCacheDependency cd = DependencyFacade.GetCategoryDependency(); // Store the output in the data cache, and Add the necessary AggregateCacheDependency object HttpRuntime.Cache.Add(key, data, cd, DateTime.Now.AddHours(categoryTimeout), Cache.NoSlidingExpiration, CacheItemPriority.High, null); } return data; }
其中:private static readonly bool enableCaching = bool.Parse(ConfigurationManager.AppSettings["EnableCaching"]);//true
这种缓存机制是最原始的把,首先我们要从cache[key]就键中找值,如果没有就缓存起来,这种数据缓存在petshop广泛应用。
这边还是来讲讲那个Sql Cache吧,那么首先要先对数据库进行配置,就是对要监控的表进行配置吧:
以PetShop 4.0为例,数据库名为MSPetShop4,则命令为:
aspnet_regsql -S localhost -E -d MSPetShop4 -ed
以下是该工具的命令参数说明:
-? 显示该工具的帮助功能;
-S 后接的参数为数据库服务器的名称或者IP地址;
-U 后接的参数为数据库的登陆用户名;
-P 后接的参数为数据库的登陆密码;
-E 当使用windows集成验证时,使用该功能;
-d 后接参数为对哪一个数据库采用SqlCacheDependency功能;
-t 后接参数为对哪一个表采用SqlCacheDependency功能;
-ed 允许对数据库使用SqlCacheDependency功能;
-dd 禁止对数据库采用SqlCacheDependency功能;
-et 允许对数据表采用SqlCacheDependency功能;
-dt 禁止对数据表采用SqlCacheDependency功能;
-lt 列出当前数据库中有哪些表已经采用sqlcachedependency功能。
以上面的命令为例,说明将对名为MSPetShop4的数据库采用SqlCacheDependency功能,且SQL Server采用了windows集成验证方式。我们还可以对相关的数据表执行aspnet_regsql命令,如:
aspnet_regsql -S localhost -E -d MSPetShop4 -t Item -et
aspnet_regsql -S localhost -E -d MSPetShop4 -t Product -et
aspnet_regsql -S localhost -E -d MSPetShop4 -t Category -et
当执行上述的四条命令后,aspnet_regsql工具会在MSPetShop4数据库中建立一个名为AspNet_SqlCacheTablesForChangeNotification的新数据库表。
具体情况请参考petshop的数据库petshop4。完。
最后补充一个API缓存(应该是对应上面的sql cache 吧)
其实这种缓存是最原始的缓存吧,先看下在Cache中存储数据的最简单的方法就是使用一个键为其赋值,就像HashTable或Dictionary对象一样:
Cache["key"] = "value"。
具体我们可以看下petshop中的SQLHelper中对SQLParameter的缓存吧:
首先定义了:paramcache的散型变量 private static Hashtable parmCache = Hashtable.Synchronized(new Hashtable());
其次,添加缓存:
/// <summary>
/// add parameter array to the cache
/// </summary>
/// <param name="cacheKey">Key to the parameter cache</param>
/// <param name="cmdParms">an array of SqlParamters to be cached</param>
public static void CacheParameters(string cacheKey, params SqlParameter[] commandParameters) {
parmCache[cacheKey] = commandParameters;//将传过来的SqlParmeter参数存放在散列表中
}
再次,调用。
/// <summary>
/// 检索HashTable的参数 HashTable是一个散列值
/// </summary>
/// <param name="cacheKey">key used to lookup parameters</param>
/// <returns>Cached SqlParamters array</returns>
public static SqlParameter[] GetCachedParameters(string cacheKey) {
SqlParameter[] cachedParms = (SqlParameter[])parmCache[cacheKey];//查看散列表中是否有这个键值
if (cachedParms == null)
return null;
SqlParameter[] clonedParms = new SqlParameter[cachedParms.Length];//为什么要复制我就不知道了
for (int i = 0, j = cachedParms.Length; i < j; i++)
clonedParms[i] = (SqlParameter)((ICloneable)cachedParms[i]).Clone();//这种复制是无法正确判断是深度复制还是浅度复制 但这并不重要
return clonedParms;
}