您的位置:首页 > 其它

TinyFrame升级之五:全局缓存的设计及实现

2014-04-15 22:41 337 查看
在任何框架中,缓存都是不可或缺的一部分,本框架亦然。在这个框架中,我们的缓存分为两部分:内存缓存和单次请求缓存。简单说来,就是一个使用微软提供的MemoryCache做扩展,并提供全局唯一实例;另一个使用微软提供的HttpContextBase做扩展,用户每发送一次请求,HttpContextBase都会被关联创建。先来看下接口约束:

usingSystem;

[code]usingSystem.Collections.Generic;
usingSystem.Linq;

usingSystem.Text;


namespaceTinyFrame.Framework.Caching

{

publicinterfaceICacheManager

{

//根据key获取缓存对象

TGet<T>(stringkey);


//设置缓存对象

voidSet(stringkey,objectdata,intcacheTime);


//查询key是否被缓存

boolIsSet(stringkey);


//从缓存移除

voidRemove(stringkey);


//缓存移除匹配

voidRemoveByPattern(stringpattern);


//清空所有缓存

voidClear();

}

}

[/code]

方法不多,但是包含了缓存的增删查。其中Get泛型方法可以通过Key返回缓存对象;Set方法可以添加缓存;IsSet方法可以检测缓存是否存在;Remove方法可以清除已有的单个缓存;RemoveByPattern可以通过正则匹配清除缓存;Clear方法则清除全部缓存。

首先是MemoryCacheManager的实现:

usingSystem;

[code]usingSystem.Collections.Generic;
usingSystem.Linq;

usingSystem.Text;

usingSystem.Runtime.Caching;

usingSystem.Text.RegularExpressions;


namespaceTinyFrame.Framework.Caching

{

publicclassMemoryCacheManager:ICacheManager

{

protectedObjectCacheCache

{

get{returnMemoryCache.Default;}

}


publicTGet<T>(stringkey)

{

return(T)Cache[key];

}


publicvoidSet(stringkey,objectdata,intcacheTime)

{

if(data==null)

return;

varpolicy=newCacheItemPolicy();

policy.AbsoluteExpiration=DateTime.Now+TimeSpan.FromMinutes(cacheTime);

Cache.Add(newCacheItem(key,data),policy);


}


publicboolIsSet(stringkey)

{

returnCache.Contains(key);

}


publicvoidRemove(stringkey)

{

Cache.Remove(key);

}


publicvoidRemoveByPattern(stringpattern)

{

varregex=newRegex(pattern,RegexOptions.Singleline

|RegexOptions.Compiled

|RegexOptions.IgnoreCase);

varkeysToRemove=newList<string>();

foreach(variteminCache)

if(regex.IsMatch(item.Key))

keysToRemove.Add(item.Key);


foreach(stringkeyinkeysToRemove)

{

Remove(key);

}

}


publicvoidClear()

{

foreach(variteminCache)

{

Remove(item.Key);

}

}

}

}

[/code]

然后是PerRequestCacheManager的实现:

usingSystem;

[code]usingSystem.Collections.Generic;
usingSystem.Linq;

usingSystem.Text;

usingSystem.Web;

usingSystem.Collections;

usingSystem.Text.RegularExpressions;


namespaceTinyFrame.Framework.Caching

{

publicclassPerRequestCacheManager:ICacheManager

{

publicPerRequestCacheManager(HttpContextBasecontext)

{

this.context=context;

}


privatereadonlyHttpContextBasecontext;


protectedvirtualIDictionaryGetItems()

{

if(context!=null)

returncontext.Items;


returnnull;

}


publicTGet<T>(stringkey)

{

varitems=GetItems();

if(items==null)

returndefault(T);


return(T)items[key];

}


publicvoidSet(stringkey,objectdata,intcacheTime)

{

varitems=GetItems();

if(items==null)

return;


if(data!=null)

{

if(items.Contains(key))

items[key]=data;

else

items.Add(key,data);

}

}


publicboolIsSet(stringkey)

{

varitems=GetItems();

if(items==null)

returnfalse;


returnitems[key]!=null;

}


publicvoidRemove(stringkey)

{

varitems=GetItems();

if(items==null)

return;


items.Remove(key);

}


publicvoidRemoveByPattern(stringpattern)

{

varitems=GetItems();

if(items==null)

return;


varenumerator=items.GetEnumerator();

varregex=newRegex(pattern,RegexOptions.Singleline

|RegexOptions.Compiled

|RegexOptions.IgnoreCase);

varkeysToRemove=newList<string>();

while(enumerator.MoveNext())

{

if(regex.IsMatch(enumerator.Key.ToString()))

{

keysToRemove.Add(enumerator.Key.ToString());

}

}


foreach(stringkeyinkeysToRemove)

{

items.Remove(key);

}

}


publicvoidClear()

{

varitems=GetItems();

if(items==null)

return;


varenumerator=items.GetEnumerator();

varkeysToRemove=newList<string>();

while(enumerator.MoveNext())

{

keysToRemove.Add(enumerator.Key.ToString());

}


foreach(stringkeyinkeysToRemove)

{

items.Remove(key);

}

}

}

}

[/code]

二者的实现方式差不多。这里我就不做过多的解释了。

如果想使用的话,直接在Autofac容器中注册一下就行了。在这次演示中,我们使用MemoryCacheManager来做缓存容器。

这里我以一个分页为例:


stringBookPaggerKey="Books-{0}-{1}-{2}-{3}";

[code]//分页查询
publicIList<Book>GetBooksPagger(intpageCount

,intcurrentIndex

,outinttotalCount

,stringpropertyName=""

,stringpropertyValue=""

)

{

IQueryable<Book>bookList=null;

intskipRows=0;

if(currentIndex>0)skipRows=currentIndex*pageCount;


if(!string.IsNullOrEmpty(propertyName))

bookList=GetBooksByConstruct(propertyName,propertyValue);

else

bookList=bookRepository.GetMany(m=>m.ID>=0);

totalCount=bookList.Count();


//returnbookList.OrderBy(p=>p.ID).Skip(skipRows).Take(pageCount).ToList();

stringkey=string.Format(BookPaggerKey,pageCount,currentIndex,propertyName,propertyValue);


returncacheManager.Get(key,()=>bookList.OrderBy(p=>p.ID).Skip(skipRows).Take(pageCount).ToList());

}

[/code]

第1行:定义了一个Cache的Key,用于标识保存ID

第23行:利用get方法检查缓存容器,如果缓存中数据不存在,则将查询数据添加到缓存;否则直接从缓存中拿出数据来。

我们来看看效果:

首先打开页面,我们换换页,目的是让页面被缓存住:





然后我们打开SQL的SQLServerProfile来进行追踪,现在,我们点击页面的刷新按钮,看看测试效果:





当我们连续刷新页面好几次,但是并未见到有新的分页查询被追踪到,说明我们的数据被缓存住了。

最后我们加个断点调试一下缓存对象,可以找到被缓存的数据:



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: