缓存项的移除通知

缓存项的移除通知

http://www.cnblogs.com/fish-li/archive/2011/12/27/2304063.html

ASP.NET Cache与一些static变量所实现的缓存效果并不相同,它的缓存项是可以根据一些特定的条件失效的,那些失效的缓存将会从内存中移除。 虽然,某些移除条件并不是由我们的代码直接解发的,但ASP.NET还是提供一种方法让我们可以在缓存项在移除时,能通知我们的代码。

注意哦:ASP.NET Cache支持移除【前】通知 和 移除【后】通知二种通知方式。

我们可以在调用Add, Insert方法时,通过参数onRemoveCallback传递一个CacheItemRemovedCallback类型的委托,以便在移除指定的缓存项时, 能够通知我们。这个委托的定义如下: 

/// <summary>
/// 定义在从 System.Web.Caching.Cache 移除缓存项时通知应用程序的回调方法。
/// </summary>
/// <param name="key">从缓存中移除的键(当初由Add, Insert传入的)。</param>
/// <param name="value">与从缓存中移除的键关联的缓存项(当初由Add, Insert传入的)。</param>
/// <param name="reason">从缓存移除项的原因。 </param>
public delegate void CacheItemRemovedCallback(string key, object value, CacheItemRemovedReason reason);


//  指定从 System.Web.Caching.Cache 对象移除项的原因。
public enum CacheItemRemovedReason
{
    //  该项是通过指定相同键的 Cache.Insert(System.String,System.Object)
    //  方法调用或 Cache.Remove(System.String) 方法调用从缓存中移除的。
    Removed = 1,

    //  从缓存移除该项的原因是它已过期。
    Expired = 2,

    //  之所以从缓存中移除该项,是因为系统要通过移除该项来释放内存。
    Underused = 3,

    //  从缓存移除该项的原因是与之关联的缓存依赖项已更改。
    DependencyChanged = 4,
}

委托的各个参数的含义以及移除原因,在注释中都有明确的解释,我也不再重复了。
我想:有很多人知道Cache的Add, Insert方法有这个参数,也知道有这个委托,但是,它们有什么用呢? 在后面的二个小节中,我将提供二个示例来演示这一强大的功能。

通常,我们会以下面这种方式从Cache中获取结果:

RunOptions options = HttpRuntime.Cache[RunOptionsCacheKey] as RunOptions;
if( options == null ) {
    // 缓存中没有,则从文件中加载
    // ..................................

    HttpRuntime.Cache.Insert(RunOptionsCacheKey, options, dep);
}
return options;

这其实也是一个惯用法了:先尝试从缓存中获取,如果没有,则从数据源中加载,并再次放入缓存。

为什么会在访问Cache时返回null呢?答案无非就是二种原因:1. 根本没有放入Cache,2. 缓存项失效被移除了。
这种写法本身是没有问题,可是,如果从数据源中加载数据的时间较长,情况会怎样呢?
显然,会影响后面第一次的访问请求。您有没有想过,如果缓存项能一直放在Cache中,那不就可以了嘛。 是的,通常来说,只要您在将一个对象放入Cache时,不指定过期时间,不指定缓存依赖,且设置为永不移除,那么对象确实会一直在Cache中, 可是,过期时间和缓存依赖也很有用哦。如何能二者兼得呢?

为了解决这个问题,微软在.net framework的3.5 SP1、3.0 SP1、2.0 SP1版本中,加入了【移除前通知】功能,不过,这个方法仅受Insert支持, 随之而来的还有一个委托和一个移除原因的枚举定义: 

/// <summary>
/// 定义一个回调方法,用于在从缓存中移除缓存项之前通知应用程序。
/// </summary>
/// <param name="key">要从缓存中移除的项的标识符。</param>
/// <param name="reason">要从缓存中移除项的原因。</param>
/// <param name="expensiveObject">此方法返回时,包含含有更新的缓存项对象。</param>
/// <param name="dependency">此方法返回时,包含新的依赖项的对象。</param>
/// <param name="absoluteExpiration">此方法返回时,包含对象的到期时间。</param>
/// <param name="slidingExpiration">此方法返回时,包含对象的上次访问时间和对象的到期时间之间的时间间隔。</param>
public delegate void CacheItemUpdateCallback(string key, CacheItemUpdateReason reason, 
                out object expensiveObject, 
                out CacheDependency dependency, 
                out DateTime absoluteExpiration, 
                out TimeSpan slidingExpiration);

/// <summary>
/// 指定要从 Cache 对象中移除缓存项的原因。
/// </summary>
public enum CacheItemUpdateReason
{
    /// <summary>
    /// 指定要从缓存中移除项的原因是绝对到期或可调到期时间间隔已到期。
    /// </summary>
    Expired = 1,
    /// <summary>
    /// 指定要从缓存中移除项的原因是关联的 CacheDependency 对象发生了更改。
    /// </summary>
    DependencyChanged = 2,
}

注意:CacheItemUpdateReason这个枚举只有二项。原因请看MSDN的解释:

与 CacheItemRemovedReason 枚举不同,此枚举不包含 Removed 或 Underused 值。可更新的缓存项是不可移除的,因而绝不会被 ASP.NET 自动移除,即使需要释放内存也是如此。

再一次提醒:有时我们确实需要缓存失效这个特性,但是,缓存失效后会被移除。 虽然我们可以让后续的请求在获取不到缓存数据时,从数据源中加载,也可以在CacheItemRemovedCallback回调委托中, 重新加载缓存数据到Cache中,但是在数据的加载过程中,Cache并不包含我们所期望的缓存数据,如果加载时间越长,这种【空缺】效果也会越明显。 这样会影响(后续的)其它请求的访问。为了保证让我们所期望的缓存数据能够一直存在于Cahce中,且仍有失效机制,我们可以使用【移除前通知】功能。

 

posted @ 2017-11-01 13:59  sky20080101  阅读(115)  评论(0)    收藏  举报