19.3 数据缓存
数据缓存是最灵活的一种缓存,它提供了一种编程方式,可通过键/值对将任意数据存储在内存中,即它的基本原则是把创建代价高的项加入到一个特定的内置集合对象Cache内。而这个对象的工作方式在很大程度上与使用应用程序状态类似。其中,与应用程序状态一样,缓存对象保存在进程内,如果应用程序域重新启动,它不会持续,同时它也不能在Web集群的服务器间共享。尽管如此,它们之间还是存在着一些区别,主要表现在如下三方面:
1)Cache对象是线程安全的。
2)缓存中的项目是自动移除的。当项目过期、项目依赖的对象或者文件发生变化,又或者是服务器内存资源不足时,ASP.NET都会自动移除缓存内的项目。
3)缓存内的项目支持依赖性。缓存对象可以链接到文件、数据库表或者其他资源,如果这些资源发生变化,则缓存对象会被自动标识为无效而移除。
19.3.1 将项添加到缓存中
要将项添加到缓存中,可以使用如下几种方法来完成。
1.通过键和值直接设置项向缓存添加项
这种方法很简单,就像将项添加到字典中一样将其添加到缓存中。如下面的示例代码所示:
Cache["Key"]="Item1";
尽管这种方法很简单,但一般不推荐使用这种方式。这种方式最大的问题是不能控制对象在缓存中的保持时间。
2.通过使用Insert方法将项添加到缓存中
其中,Insert方法有如下几种重载:
1)public void Insert(string key, Object value)方法表示向Cache对象插入项,该项带有一个缓存键引用其位置,并使用CacheItemPriority枚举提供的默认值。也就是说,它没有文件或缓存依赖项,其优先级为Default,可调到期值为NoSlidingExpiration,绝对到期值为NoAbsoluteExpiration。
其中,key参数用于引用该项的缓存键;value参数表示要插入缓存中的对象。如下面的示例代码所示:
Cache.Insert("Key","Item1");
2)public void Insert(string key, Object value, CacheDependency dependencies)方法表示向Cache中插入具有文件依赖项或键依赖项的对象。其中,dependencies参数表示所插入对象的文件依赖项或缓存键依赖项。当任何依赖项更改时,该对象即无效,并从缓存中移除。如果没有依赖项,则此参数包含null。
下面的示例演示如何向应用程序的缓存中插入项,该项具有XML配置文件的缓存依赖项。如下面的代码所示:
Cache.Insert("Key",obj,
new CacheDependency(Server.MapPath("myconfig.xml")));
除此之外,还通过使用AggregateCacheDependency类缓存中的项依赖于多个元素(这也就是所说的聚合依赖项)。AggregateCacheDependency类监视依赖项对象的集合,以便在任何依赖项对象更改时,该缓存项都会自动移除。其中,这些对象可以是CacheDependency对象、SqlCache Dependency对象、从CacheDependency派生的自定义对象或这些对象的任意组合。
虽然AggregateCacheDependency类继承自CacheDependency类,但它们两者却存在着许多不同之处。其中,最大的区别在于AggregateCacheDependency类允许将不同类型的多个依赖项与单个缓存项关联。例如,如果创建一个从SQL Server数据库表和XML文件导入数据的页,则可创建一个SqlCacheDependency对象来表示数据库表的依赖项,以及一个CacheDependency来表示XML文件的依赖项。可创建AggregateCacheDependency类的一个实例,将每个依赖项添加到该类中,而不是为每个依赖项调用Cache.Insert方法。然后,可使用单个Insert调用使该页依赖于AggregateCacheDependency实例。
如下面的代码示例演示如何创建多个依赖项,它向缓存中名为Item1的另一个项添加键依赖项,向名为XMLFile.xml的文件添加文件依赖项。
System.Web.Caching.CacheDependency dep1=
new System.Web.Caching.CacheDependency(
Server.MapPath("XMLFile.xml"));
string[]keyDependencies2={"Item1"};
System.Web.Caching.CacheDependency dep2=
new System.Web.Caching.CacheDependency(null, keyDependencies2);
System.Web.Caching.AggregateCacheDependency aggDep=
new System.Web.Caching.AggregateCacheDependency();
aggDep.Add(dep1);
aggDep.Add(dep2);
Cache.Insert("Key","Item2",aggDep);
3)public void Insert(string key, Object value, CacheDependency dependencies, DateT ime absoluteExpiration, TimeSpan slidingExpiration)方法表示向Cache中插入具有依赖项和到期策略的对象。其中absoluteExpiration参数表示所插入对象将到期并被从缓存中移除的时间。要避免可能的本地时间问题(例如从标准时间改为夏时制),请使用UtcNow而不是Now作为此参数值。如果使用绝对到期,则slidingExpiration参数必须为NoSlidingExpiration。如下面的示例演示如何向应用程序的缓存中插入具有绝对到期的项:
Cache.Insert("Key",obj, null, DateTime.Now.AddMinutes(2),
System.Web.Caching.Cache.NoSlidingExpiration);
slidingExpiration参数表示最后一次访问所插入对象时与该对象到期时之间的时间间隔。如果该值等效于20分钟,则对象在最后一次被访问20分钟之后将到期并被从缓存中移除。如果使用可调到期,则absoluteExpiration参数必须为NoAbsoluteExpiration。如下面的示例演示如何向缓存中插入具有可调整到期的项:
Cache.Insert("Key",obj, null,
System.Web.Caching.Cache.NoAbsoluteExpiration,
TimeSpan.FromSeconds(10));
值得注意的是,虽然ASP.NET允许设置可调整到期策略或者绝对到期策略,但只能够选择其中一个。如果将Insert方法的slidingExpiration参数的值设置为NoSlidingExpiration,则表示禁用可调整到期;如果将slidingExpiration参数的值设置为大于Zero,则absoluteExpiration参数设置为Now加slidingExpiration参数中包含的值;如果在absoluteExpiration参数指定的时间之前从缓存请求该项,该项将再次放入缓存,并且absoluteExpiration将再次设置为DateTime.Now加上slidingExpiration参数中包含的值;如果在absoluteExpiration参数中的日期以前并未从缓存中请求该项,则从缓存移除该项。该项的优先级为Default。
4)public void Insert(string key, Object value, CacheDependency dependencies, DateT ime absoluteExpiration, TimeSpan slidingExpiration, CacheItemUpdateCallback onUpdateCallback)方法表示将对象与依赖项、到期策略以及可用于在从缓存中移除项之前通知应用程序的委托一起插入到Cache对象中。其中,onUpdateCallback参数表示从缓存中移除对象之前将调用的委托,可以使用它来更新缓存项并确保缓存项不会从缓存中移除。使用示例如下面的代码所示:
Cache.Insert("Key",obj, null,
System.Web.Caching.Cache.NoAbsoluteExpiration,
TimeSpan.FromSeconds(10),onUpdate);
5)public void Insert(string key, Object value, CacheDependency dependencies, DateT ime absoluteExpiration, TimeSpan slidingExpiration, CacheItemPriority priority, CacheItemRemovedCallback onRemoveCallback)方法表示向Cache对象中插入对象,且具有依赖项、到期策略、优先级策略以及一个委托(可用于在从Cache移除插入项时通知应用程序)。其中,priority参数表示该对象相对于缓存中存储的其他项的成本的优先级,由CacheItemPriority枚举表示,如表19-4所示。该值由缓存在退出对象时使用,具有较低成本优先级的对象在具有较高成本优先级的对象之前被从缓存移除。
onRemoveCallback参数表示在从缓存中移除对象时将调用的委托,当从缓存中删除应用程序的对象时,可使用它来通知应用程序。
Cache.Insert("Key",obj, null, DateTime.Now.AddMinutes(2),
TimeSpan.Zero, CacheItemPriority.High, onRemove);
3.使用Add方法向缓存添加项
该方法可以将指定项添加到Cache对象,该对象具有依赖项、到期策略、优先级策略以及一个委托(可用于在从Cache移除插入项时通知应用程序)。其中,该方法的原型如下:
public Object Add(
string key,
Object value,
CacheDependency dependencies,
DateTime absoluteExpiration,
TimeSpan slidingExpiration,
CacheItemPriority priority,
CacheItemRemovedCallback onRemoveCallback
)
下面的示例创建一个AddItemToCache方法。调用此方法时,它将itemRemoved属性设置为false,并向CacheItemRemovedCallback委托的新实例注册onRemove方法。在RemovedCallback方法中使用委托的签名。然后AddItemToCache方法检查与缓存中的Key键关联的值。如果该值为null,则Add方法在缓存中放置一项,其键为Key,值为Item1,绝对到期时间为60秒,并具有高缓存优先级。它还将onRemove方法作为参数,这允许在从缓存中移除此项时调用RemovedCallback方法。如下面的代码所示:
public void AddItemToCache(Object sender, EventArgs e)
{
itemRemoved=false;
onRemove=
new CacheItemRemovedCallback(this.RemovedCallback);
if(Cache["Key"]==null)
{
Cache.Add("Key","Item1",null,
DateTime.Now.AddSeconds(60),
Cache.NoSlidingExpiration,
CacheItemPriority.High, onRemove);
}
}
19.3.2 检索缓存项的值
我们知道,ASP.NET缓存中的数据是易失的,即不能永久保存。其中,只要发生缓存已满、该项已过期与依赖项发生更改等现象之一,缓存中的数据就可能会自动移除。因此,在使用缓存项时应该首先确定该项是否在缓存中。如果不在,则应将它重新添加到缓存中,然后检索该项。
要从缓存中检索数据,就应指定存储缓存项的键。可以通过在Cache对象中进行检查来确定该项是否不为null。如果该项存在,则将它分配给变量。否则,重新创建该项,将它添加到缓存中,然后访问它。
下面的示例演示如何从缓存中检索名为Key的项。其代码如下所示:
if(Cache["Key"]==null)
{
Cache.Insert("Key","Hello, World.");
}
Response.Write(Cache["Key"]);
19.3.3 从缓存中删除项
其实,ASP.NET除了允许从缓存中自动移除项之外,还可以显式地移除项。其方法很简单,只需要调用Remove方法,以传递要移除的项的键就可以了。下面的示例演示如何移除键为Key的项。其代码如下所示:
Cache.Remove("Key");
值得注意的是,如果调用Insert方法,并向缓存中添加与现有项同名的项,则将从缓存中删除该旧项。