所幸的是,ASP.NET作为基于.Net Framework的WEB开发技术,它也享用着.Net Framework的优越性,.Net Framework为我们提供了良好的Cache技术,使我们能开发出速度更快、用户体验更好的WEB应用。命名空间System.Web.Caching提供了Cache类,其Cache的有效性依赖分以下三种情况:
1. 时间点(指定时间点内有效);
2. KEY值(KEY值作Cache项标识);
3. 文件或目录(指定文件或目录变更,则原Cache项不可用);
下面我就结合实际开发的应用跟大家分享一下使用Cache来提高ASP.NET应用的性能。
我们在开发中常常会遇到读取记录列表(例如最近更新的新闻列表Top N)、记录本身(例如一条新闻),用户访问的时候,这样的信息是否每次都要重复从数据库中读取呢?聪明的你可能知道,这完全是没必要的。
我们为了方便处理,不防设计一个SiteCache类(借鉴了CS中的CSCache.cs),并提供若干静态方法,来负责处理Cache项的添加和删除。下面给出类图:
![SiteCache.PNG](https://www.cnblogs.com/images/cnblogs_com/aspsir/SiteCache.PNG)
代码:
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
1
using System;
2
using System.Collections;
3
using System.Text.RegularExpressions;
4
using System.Web;
5
using System.Web.Caching;
6![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
7
namespace Ycweb.Components
8![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
9
public class SiteCache
10![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
11
private static readonly Cache _cache;
12
public static readonly int DayFactor;
13
private static int Factor;
14
public static readonly int HourFactor;
15
public static readonly int MinuteFactor;
16![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
17
static SiteCache()
18![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
19
DayFactor = 17280;
20
HourFactor = 720;
21
MinuteFactor = 12;
22
Factor = 5;
23
_cache = HttpRuntime.Cache;
24
}
25![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
26
private SiteCache()
27![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
28
}
29![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
30
public static void Clear()
31![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
32
IDictionaryEnumerator enumerator = _cache.GetEnumerator();
33
while (enumerator.MoveNext())
34![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
35
_cache.Remove(enumerator.Key.ToString());
36
}
37
}
38![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
39
public static object Get(string key)
40![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
41
return _cache[key];
42
}
43![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
44
public static void Insert(string key, object obj)
45![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
46
Insert(key, obj, null, 1);
47
}
48![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
49
public static void Insert(string key, object obj, int seconds)
50![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
51
Insert(key, obj, null, seconds);
52
}
53![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
54
public static void Insert(string key, object obj, CacheDependency dep)
55![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
56
Insert(key, obj, dep, HourFactor*12);
57
}
58![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
59
public static void Insert(string key, object obj, int seconds, CacheItemPriority priority)
60![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
61
Insert(key, obj, null, seconds, priority);
62
}
63![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
64
public static void Insert(string key, object obj, CacheDependency dep, int seconds)
65![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
66
Insert(key, obj, dep, seconds, CacheItemPriority.Normal);
67
}
68![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
69
public static void Insert(string key, object obj, CacheDependency dep, int seconds, CacheItemPriority priority)
70![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
71
if (obj != null)
72![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
73
_cache.Insert(key, obj, dep, DateTime.Now.AddSeconds((double) (Factor*seconds)), TimeSpan.Zero, priority, null);
74
}
75
}
76![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
77
public static void Max(string key, object obj)
78![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
79
Max(key, obj, null);
80
}
81![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
82
public static void Max(string key, object obj, CacheDependency dep)
83![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
84
if (obj != null)
85![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
86
_cache.Insert(key, obj, dep, DateTime.MaxValue, TimeSpan.Zero, CacheItemPriority.AboveNormal, null);
87
}
88
}
89![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
90
public static void MicroInsert(string key, object obj, int secondFactor)
91![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
92
if (obj != null)
93![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
94
_cache.Insert(key, obj, null, DateTime.Now.AddSeconds((double) (Factor*secondFactor)), TimeSpan.Zero);
95
}
96
}
97![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
98
public static void Remove(string key)
99![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
100
_cache.Remove(key);
101
}
102![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
103
public static void RemoveByPattern(string pattern)
104![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
105
IDictionaryEnumerator enumerator = _cache.GetEnumerator();
106
Regex regex1 = new Regex(pattern, RegexOptions.Singleline | RegexOptions.Compiled | RegexOptions.IgnoreCase);
107
while (enumerator.MoveNext())
108![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
109
if (regex1.IsMatch(enumerator.Key.ToString()))
110![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
111
_cache.Remove(enumerator.Key.ToString());
112
}
113
}
114
}
115![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
116
public static void ReSetFactor(int cacheFactor)
117![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
118
Factor = cacheFactor;
119
}
120![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
121![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
122![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
123
}
124
}
其实该类主要就是利用前文所提及的关于Cache依赖项的第一点与第二点的特性来维护我们自己的Cache项。
有了SiteCache类,接下来看看如何使用它。还是以读取新闻TonN列表为例:
1
public static RecordSet GetNewsSetTopN(string classCode,int topN,SortPostsBy orderBy, SortOrder sortOrder, string language)
2![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
3
string cacheKey = string.Format("NewsSetTopN-LG:{0}:CC:{1}:TN:{2}:OB:{3}:SO:{4}", language,classCode,topN.ToString(), orderBy.ToString(),sortOrder.ToString());
4
5
//从上下文中读缓存项
6
RecordSet newsSet = HttpContext.Current.Items[cacheKey] as RecordSet;
7
if (newsSet !=null)
8![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
9
//从HttpRuntime.Cache读缓存项
10
newsSet = SiteCache.Get(cacheKey) as RecordSet;
11
if (newsSet == null)
12![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
13
//直接从数据库从读取
14
CommonDataProvider dp=CommonDataProvider.Instance();
15
newsSet =dp.GetNewsSetTopN(language,classCode,topN,orderBy,sortOrder);
16
//并将结果缓存到HttpRuntime.Cache中
17
SiteCache.Insert(cacheKey, newsSet, 60, CacheItemPriority.Normal);
18
}
19
20
}
21
return newsSet;
22
}
这样在5分钟内就不用重复访问数据库了来读该列表了,当然,也有人会问,如果在这5分钟内某条新闻删除了或修改了怎么办,没关系,我们在删除或修改时可以根据Cache KEY来强制删除该Cache项,当然,如果你觉得你对列表的时效性不是特别在意,你可以不强制删除该Cache项,让Cache项定义的时间点自动失效。当然,最好还是提供一个方法按匹配模式项来强行删除Cache项就可以了,例如:
1![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
/// <summary>
2
/// 删除匹配的NewsSetTopN列表的Cache项
3
/// </summary>
4
public static void ClearNewsSetTopNCache(string language,string classCode,int topN)
5![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
6
string cacheKey = string.Format("NewsSetTopN-LG:{0}:CC:{1}:TN:{2}",language,classCode,topN.ToString());
7
SiteCache.RemoveByPattern(cacheKey);
8
}
9![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
发布新闻后调用静态方法ClearNewsSetTopNCache()强行清除原来的TopN缓存项,例如:
1![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
/// <summary>
2
/// 发布(新建)新闻
3
/// </summary>
4
/// <param name="post">新闻实例</param>
5
/// <returns>返回状态</returns>
6
public static int Create(News post)
7![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
8
int status;
9
CommonDataProvider dp=CommonDataProvider.Instance();
10
dp.CreateUpdateDeleteNews(post, DataAction.Create, out status);
11
//强制清除匹配的缓存项
12
ClearNewsSetTopNCache (post.Language, post.ClassCode,Globals.GetSiteSetting.NewsListTopN);
13
return status;
14
}
v