TinyFrame升级之五:全局缓存的设计及实现
在任何框架中,缓存都是不可或缺的一部分,本框架亦然。在这个框架中,我们的缓存分为两部分:内存缓存和单次请求缓存。简单说来,就是一个使用微软提供的MemoryCache做扩展,并提供全局唯一实例;另一个使用微软提供的HttpContextBase做扩展,用户每发送一次请求,HttpContextBase都会被关联创建。先来看下接口约束:
1: using System;
2: using System.Collections.Generic;
3: using System.Linq;
4: using System.Text;
5:
6: namespace TinyFrame.Framework.Caching
7: {
8: public interface ICacheManager
9: {
10: //根据key获取缓存对象
11: T Get<T>(string key);
12:
13: //设置缓存对象
14: void Set(string key, object data, int cacheTime);
15:
16: //查询key是否被缓存
17: bool IsSet(string key);
18:
19: //从缓存移除
20: void Remove(string key);
21:
22: //缓存移除匹配
23: void RemoveByPattern(string pattern);
24:
25: //清空所有缓存
26: void Clear();
27: }
28: }
方法不多,但是包含了缓存的增删查。其中Get泛型方法可以通过Key返回缓存对象;Set方法可以添加缓存;IsSet方法可以检测缓存是否存在;Remove方法可以清除已有的单个缓存;RemoveByPattern可以通过正则匹配清除缓存;Clear方法则清除全部缓存。
首先是MemoryCacheManager的实现:
1: using System;
2: using System.Collections.Generic;
3: using System.Linq;
4: using System.Text;
5: using System.Runtime.Caching;
6: using System.Text.RegularExpressions;
7:
8: namespace TinyFrame.Framework.Caching
9: {
10: public class MemoryCacheManager:ICacheManager
11: {
12: protected ObjectCache Cache
13: {
14: get { return MemoryCache.Default; }
15: }
16:
17: public T Get<T>(string key)
18: {
19: return (T)Cache[key];
20: }
21:
22: public void Set(string key, object data, int cacheTime)
23: {
24: if (data == null)
25: return;
26: var policy = new CacheItemPolicy();
27: policy.AbsoluteExpiration = DateTime.Now + TimeSpan.FromMinutes(cacheTime);
28: Cache.Add(new CacheItem(key,data),policy);
29:
30: }
31:
32: public bool IsSet(string key)
33: {
34: return Cache.Contains(key);
35: }
36:
37: public void Remove(string key)
38: {
39: Cache.Remove(key);
40: }
41:
42: public void RemoveByPattern(string pattern)
43: {
44: var regex = new Regex(pattern, RegexOptions.Singleline
45: | RegexOptions.Compiled
46: | RegexOptions.IgnoreCase);
47: var keysToRemove = new List<string>();
48: foreach (var item in Cache)
49: if (regex.IsMatch(item.Key))
50: keysToRemove.Add(item.Key);
51:
52: foreach (string key in keysToRemove)
53: {
54: Remove(key);
55: }
56: }
57:
58: public void Clear()
59: {
60: foreach (var item in Cache)
61: {
62: Remove(item.Key);
63: }
64: }
65: }
66: }
然后是PerRequestCacheManager的实现:
1: using System;
2: using System.Collections.Generic;
3: using System.Linq;
4: using System.Text;
5: using System.Web;
6: using System.Collections;
7: using System.Text.RegularExpressions;
8:
9: namespace TinyFrame.Framework.Caching
10: {
11: public class PerRequestCacheManager : ICacheManager
12: {
13: public PerRequestCacheManager(HttpContextBase context)
14: {
15: this.context = context;
16: }
17:
18: private readonly HttpContextBase context;
19:
20: protected virtual IDictionary GetItems()
21: {
22: if (context != null)
23: return context.Items;
24:
25: return null;
26: }
27:
28: public T Get<T>(string key)
29: {
30: var items = GetItems();
31: if (items == null)
32: return default(T);
33:
34: return (T)items[key];
35: }
36:
37: public void Set(string key, object data, int cacheTime)
38: {
39: var items = GetItems();
40: if (items == null)
41: return;
42:
43: if (data != null)
44: {
45: if (items.Contains(key))
46: items[key] = data;
47: else
48: items.Add(key, data);
49: }
50: }
51:
52: public bool IsSet(string key)
53: {
54: var items = GetItems();
55: if (items == null)
56: return false;
57:
58: return items[key] != null;
59: }
60:
61: public void Remove(string key)
62: {
63: var items = GetItems();
64: if (items == null)
65: return;
66:
67: items.Remove(key);
68: }
69:
70: public void RemoveByPattern(string pattern)
71: {
72: var items = GetItems();
73: if (items == null)
74: return;
75:
76: var enumerator = items.GetEnumerator();
77: var regex = new Regex(pattern, RegexOptions.Singleline
78: | RegexOptions.Compiled
79: | RegexOptions.IgnoreCase);
80: var keysToRemove = new List<string>();
81: while (enumerator.MoveNext())
82: {
83: if (regex.IsMatch(enumerator.Key.ToString()))
84: {
85: keysToRemove.Add(enumerator.Key.ToString());
86: }
87: }
88:
89: foreach (string key in keysToRemove)
90: {
91: items.Remove(key);
92: }
93: }
94:
95: public void Clear()
96: {
97: var items = GetItems();
98: if (items == null)
99: return;
100:
101: var enumerator = items.GetEnumerator();
102: var keysToRemove = new List<string>();
103: while (enumerator.MoveNext())
104: {
105: keysToRemove.Add(enumerator.Key.ToString());
106: }
107:
108: foreach (string key in keysToRemove)
109: {
110: items.Remove(key);
111: }
112: }
113: }
114: }
二者的实现方式差不多。这里我就不做过多的解释了。
如果想使用的话,直接在Autofac容器中注册一下就行了。在这次演示中,我们使用MemoryCacheManager来做缓存容器。
这里我以一个分页为例:
1: string BookPaggerKey = "Books-{0}-{1}-{2}-{3}";
2: //分页查询
3: public IList<Book> GetBooksPagger(int pageCount
4: , int currentIndex
5: , out int totalCount
6: , string propertyName=""
7: , string propertyValue=""
8: )
9: {
10: IQueryable<Book> bookList = null;
11: int skipRows = 0;
12: if (currentIndex > 0) skipRows = currentIndex * pageCount;
13:
14: if (!string.IsNullOrEmpty(propertyName))
15: bookList = GetBooksByConstruct(propertyName, propertyValue);
16: else
17: bookList = bookRepository.GetMany(m => m.ID >= 0);
18: totalCount = bookList.Count();
19:
20: //return bookList.OrderBy(p => p.ID).Skip(skipRows).Take(pageCount).ToList();
21: string key = string.Format(BookPaggerKey, pageCount, currentIndex, propertyName, propertyValue);
22:
23: return cacheManager.Get(key, () => bookList.OrderBy(p => p.ID).Skip(skipRows).Take(pageCount).ToList());
24: }
第1行:定义了一个Cache的Key,用于标识保存ID
第23行:利用get方法检查缓存容器,如果缓存中数据不存在,则将查询数据添加到缓存;否则直接从缓存中拿出数据来。
我们来看看效果:
首先打开页面,我们换换页,目的是让页面被缓存住:

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

当我们连续刷新页面好几次,但是并未见到有新的分页查询被追踪到,说明我们的数据被缓存住了。
最后我们加个断点调试一下缓存对象,可以找到被缓存的数据:

TinyFrame升级之五:全局缓存的设计及实现的更多相关文章
- .NET 缓存模块设计
上一篇谈了我对缓存的概念,框架上的理解和看法,这篇承接上篇讲讲我自己的缓存模块设计实践. 基本的缓存模块设计 最基础的缓存模块一定有一个统一的CacheHelper,如下: public interf ...
- 《深入理解mybatis原理7》 MyBatis的二级缓存的设计原理
<深入理解mybatis原理> MyBatis的二级缓存的设计原理 MyBatis的二级缓存是Application级别的缓存,它可以提高对数据库查询的效率,以提高应用的性能.本文将全面分 ...
- Redis缓存的设计、性能、应用与数据集群同步
Redis缓存的设计.性能.应用与数据集群同步 http://youzhixueyuan.com/design-performance-and-application-of-redis-cache.h ...
- 简单服务端缓存API设计
Want 我们希望设计一套缓存API,适应不同的缓存产品,并且基于Spring框架完美集成应用开发. 本文旨在针对缓存产品定义一个轻量级的客户端访问框架,目标支持多种缓存产品,面向接口编程,目前支持简 ...
- 《深入理解mybatis原理》 MyBatis的二级缓存的设计原理
MyBatis的二级缓存是Application级别的缓存,它可以提高对数据库查询的效率,以提高应用的性能.本文将全面分析MyBatis的二级缓存的设计原理. 如上图所示,当开一个会话时,一个SqlS ...
- Redis缓存策略设计及常见问题
Redis缓存设计及常见问题 缓存能够有效地加速应用的读写速度,同时也可以降低后端负载,对日常应用的开发至关重要.下面会介绍缓存使用技巧和设计方案,包含如下内容:缓存的收益和成本分析.缓存更新策略的选 ...
- mybatis深入理解(六)-----MyBatis的二级缓存的设计原理
MyBatis的二级缓存是Application级别的缓存,它可以提高对数据库查询的效率,以提高应用的性能.本文将全面分析MyBatis的二级缓存的设计原理. 1.MyBatis的缓存机制整体设计以及 ...
- 单例设计模式全局缓存accessToken
使用微信JS-SDK开发的小伙伴们,看文档经常会看到这样一句话:(下面是微信开发文档的一部分原话截图) 这句话就是:开发者必须在自己的服务全局缓存access_token,jsapi_ticket 下 ...
- IOS编程 图片缓存模块设计
手机客户端为什么会留存下来?而不是被一味的Wap替代掉?因为手机客户端有Wap无可替代的优势,就是自身较强的计算能力. 手机中不可避免的一环:图片缓存,在软件的整个运行过程中显得尤为重要. 先简单说一 ...
随机推荐
- BitTorrent Sync - 神奇的文件同步软件,无需服务器让多台电脑互相同步!
176,487 微博 腾讯 空间 微信 141 49 如今人们对文件备份和同步的需求已经越来越强烈了.像 Dropbox 一样的云存储网盘有很多,但它们都有一个局限性,就是所有的文件都得经过它们的服务 ...
- Linux老是提示compat-libstdc++ is not installed的原因
在一Linux服务器上检查是否安装了一些包时,遇到老是提示"package compat-libstdc++ is not installed" [root@DB-Server ~ ...
- 已知2个一维数组:a[]={3,4,5,6,7},b[]={1,2,3,4,5,6,7};把数组a与数组b ,对应的元素乘积再赋值给数组b,如:b[2]=a[2]*b[2];最后输出数组b的元素。
int[]a={3,4,5,6,7}; int[]b={1,2,3,4,5,6,7}; int[] arry=new int[7]; System.out.print("数组b[]={&qu ...
- Jmeter默认报告优化
一.本文目的: 之前写了两篇文章搭建持续集成接口测试平台(Jenkins+Ant+Jmeter)和ANT批量执行Jmeter脚本,功能实现上都没有什么问题,但是最后生成的报告有一点小问题,虽然不影响使 ...
- 知道创宇研发技能表v3.1
by @知道创宇(www.knownsec.com) @余弦 & 404团队 后续动态请关注微信公众号:Lazy-Thought 说明 关于知道创宇 知行合一 | 守正出奇 知道创宇是一家黑客 ...
- MicroCube 风力发电装置
这个叫做 MicroCube 的发电装置其实是一套「小型风扇+发电机」的组合,能够输出三相交流电,之后转换成直流电给电池组充电. 一个 MicroCube 长宽高均为 23 厘米左右,重约 1.4 公 ...
- win7下Qt5使用mysql C++编程配置
先下载mysql的库文件链接:http://files.cnblogs.com/files/xiaobo-Linux/mysql.zip 把两个文件放入 Qt目录\Qt5.5.0\5.5\mingw4 ...
- 给深度学习入门者的Python快速教程 - numpy和Matplotlib篇
始终无法有效把word排版好的粘贴过来,排版更佳版本请见知乎文章: https://zhuanlan.zhihu.com/p/24309547 实在搞不定博客园的排版,排版更佳的版本在: 给深度学习入 ...
- HDU 5139 Formula --离线处理
题意就不说了,求公式. 解法: 稍加推导能够得出 : f(n) = n! * f(n-1) , 即其实是求: ∏(n!) ,盲目地存下来是不行的,这时候看见条件: 数据组数 <= 100000 ...
- NOIP2013积木大赛
题目描述 春春幼儿园举办了一年一度的“积木大赛”.今年比赛的内容是搭建一座宽度为n的大厦,大厦可以看成由n块宽度为1的积木组成,第i块积木的最终高度需要是hi. 在搭建开始之前,没有任何积木(可以看成 ...