惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

IT之家
IT之家
Last Week in AI
Last Week in AI
博客园_首页
酷 壳 – CoolShell
酷 壳 – CoolShell
博客园 - 叶小钗
大猫的无限游戏
大猫的无限游戏
人人都是产品经理
人人都是产品经理
V
Visual Studio Blog
宝玉的分享
宝玉的分享
博客园 - Franky
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
月光博客
月光博客
T
Tailwind CSS Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
量子位
博客园 - 聂微东
S
SegmentFault 最新的问题
博客园 - 司徒正美
罗磊的独立博客
V
V2EX
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
美团技术团队
小众软件
小众软件
Jina AI
Jina AI

博客园 - 宝气狗

【摄影】2008年06月07日西塘 【摄影】2008年05月24日大明山 2007年11月——感受黄山,天下无山。 将基础数据类型与字节数组相互转换 托管/非托管类型对照 【数据库】遍历XML根下的一级节点 - 宝气狗 - 博客园 css中的nowrap 2007年9月15日 九溪-五云山-梅家坞之行 宝气狗的新闻博开始使用http://webbased.cn [设计模式] 15.Command 命令模式 [设计模式] 22.State 状态模式 [设计模式] 23.Strategy 策略模式 值类型装箱拆箱需要注意的地方 CLR如何控制类型中字段的布局 MSIL指令速查 内存一致性问题(续一) 内存一致性问题 如何循序渐进向DotNet架构师发展 关于将Queue中的数据拼接成xml的经验
Enterprise Library中缓存过期策略探究
宝气狗 · 2007-10-27 · via 博客园 - 宝气狗

今天遇到一个错误,描述如下:
缓存管理器:CacheManager _cache
if(!_cache.Contains(key))
{
    //...做一些加载缓存操作
    //_cache.Add(key, obj,  CacheItemPriority.Normal, new RefreshAction(),  new SlidingTime(TimeSpan.FromSeconds(1)));
}
return _cache[key];
在缓存加载时,使用了过期策略,为了方便测试,我使用了1秒钟就过期。

在加载缓存操作并Add后(理论上我确保了_cache中一定含有key值),_cache[key]却出现了null。
在程序中的可能性反映是:未将对象引用设置到对象的实例。

为什么会出现这样的错误呢?经研究发现,这是缓存过期策略造成的。即我写的RefreshAction类,此类继承了ICacheItemRefreshAction接口,用来在缓存过期时做一些处理。
[Serializable]
public class ItemCacheRefreshAction : ICacheItemRefreshAction
{
 public void Refresh(string removeKey, object expiredValue, CacheItemRemovedReason removalReason)
 {
  Item item = (Item)expiredValue;
  Console.WriteLine(item.Name + " " + item.Guid + "已过期,过期原因:" + removalReason);
 }
}
那么什么时候会命中这个回调呢?其实官方手册中已经有过描述,最常见的有两种情况会命中这个回调。
一. 在cache.config缓存配置文件中的扫描策略,其中expirationPollFrequencyInSeconds指定了扫描间隔,当时间达到时,就会命中这个回调,即会让缓存过期。
二. 在Add时,指定了过期策略,其中new SlidingTime(TimeSpan.FromSeconds(1))指定了在1秒钟后过期,当在上面第一条中的扫描器未到时间,而此缓存又过期时,再次访问缓存时,就会强行命中此回调,即让缓存过期。这是企业库缓存机制较隐蔽的陷阱。下面举个例子讲讲第二条。
1. 扫描器初始化,且时间假设为100分钟,为了测试第二条,我故意设了一个很大的间隔时间
2. Key = 1, Value = 1,我在Add时指定了1秒钟的过期时间
3. 第一次访问_cache[1],会进行缓存加载,然后正常出结果
4. 等待1秒钟以上
5. 第二次访问_cache[1]时,命中了上面的回调,缓存过期了。
由此我的错误就有了解释,我错误的使用了if(!_cache.Contains(key))来判断是否存在缓存,此时不会触发过期机制,而后我又直接返回了_cache[key],其实这时已经到了上面的第5步,即缓存过期了。于是我的null便产生了。

掌握了缓存过期策略,解决办法就比较简单了。
Object obj = _cache[key];
if(obj == null)
{
    //...做一些加载缓存操作
    //_cache.Add(key, obj,  CacheItemPriority.Normal, new RefreshAction(),  new SlidingTime(TimeSpan.FromSeconds(1)));
}
obj = _cache[key];
return obj;

用obj == null替换了Contains语句,其实就是保证过期的命中,其后再根据是否为null来加载缓存

Cache Application Block缓存过期机制需要深入研究,才能充分体现这个模块的易用和强大。 

为次我写了个简单的Demo,放在附件中点击下载此文件,下载后将.txt改为.rar解压即可。
注意修改cs文件中配置文件的路径E:\\cs\\CacheApplicationBlock\\cache.config