雖然現在已經是寬帶時代,小貓已經離我們漸漸遠去,可作為web應用開發者來說,我們仍然有責任和義務不斷地通過技術手段來優化web應用性能,讓用戶瀏覽時少一些等待,多一些爽快。
所幸的是,asp.net作為基于.net framework的技術,它也享用著.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.cs
1using system;
2using system.collections;
3using system.text.regularexpressions;
4using system.web;
5using system.web.caching;
6
7namespace ycweb.components
8{
9 public class sitecache
10 {
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
17 static sitecache()
18 {
19 dayfactor = 17280;
20 hourfactor = 720;
21 minutefactor = 12;
22 factor = 5;
23 _cache = httpruntime.cache;
24 }
25
26 private sitecache()
27 {
28 }
29
30 public static void clear()
31 {
32 idictionaryenumerator enumerator = _cache.getenumerator();
33 while (enumerator.movenext())
34 {
35 _cache.remove(enumerator.key.tostring());
36 }
37 }
38
39 public static object get(string key)
40 {
41 return _cache[key];
42 }
43
44 public static void insert(string key, object obj)
45 {
46 insert(key, obj, null, 1);
47 }
48
49 public static void insert(string key, object obj, int seconds)
50 {
51 insert(key, obj, null, seconds);
52 }
53
54 public static void insert(string key, object obj, cachedependency dep)
55 {
56 insert(key, obj, dep, hourfactor*12);
57 }
58
59 public static void insert(string key, object obj, int seconds, cacheitempriority priority)
60 {
61 insert(key, obj, null, seconds, priority);
62 }
63
64 public static void insert(string key, object obj, cachedependency dep, int seconds)
65 {
66 insert(key, obj, dep, seconds, cacheitempriority.normal);
67 }
68
69 public static void insert(string key, object obj, cachedependency dep, int seconds, cacheitempriority priority)
70 {
71 if (obj != null)
72 {
73 _cache.insert(key, obj, dep, datetime.now.addseconds((double) (factor*seconds)), timespan.zero, priority, null);
74 }
75 }
76
77 public static void max(string key, object obj)
78 {
79 max(key, obj, null);
80 }
81
82 public static void max(string key, object obj, cachedependency dep)
83 {
84 if (obj != null)
85 {
86 _cache.insert(key, obj, dep, datetime.maxvalue, timespan.zero, cacheitempriority.abovenormal, null);
87 }
88 }
89
90 public static void microinsert(string key, object obj, int secondfactor)
91 {
92 if (obj != null)
93 {
94 _cache.insert(key, obj, null, datetime.now.addseconds((double) (factor*secondfactor)), timespan.zero);
95 }
96 }
97
98 public static void remove(string key)
99 {
100 _cache.remove(key);
101 }
102
103 public static void removebypattern(string pattern)
104 {
105 idictionaryenumerator enumerator = _cache.getenumerator();
106 regex regex1 = new regex(pattern, regexoptions.singleline | regexoptions.compiled | regexoptions.ignorecase);
107 while (enumerator.movenext())
108 {
109 if (regex1.ismatch(enumerator.key.tostring()))
110 {
111 _cache.remove(enumerator.key.tostring());
112 }
113 }
114 }
115
116 public static void resetfactor(int cachefactor)
117 {
118 factor = cachefactor;
119 }
120
121
122
123 }
124}
其實該類主要就是利用前文所提及的關于cache依賴項的第一點與第二點的特性來維護我們自己的cache項。
有了sitecache類,接下來看看如何使用它。還是以讀取新聞tonn列表為例:
1public static recordset getnewssettopn(string classcode,int topn,sortpostsby orderby, sortorder sortorder, string language)
2{
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 {
9 //從httpruntime.cache讀緩存項
10 newsset = sitecache.get(cachekey) as recordset;
11 if (newsset == null)
12 {
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 }
21return newsset;
22}
這樣在5分鐘內就不用重復訪問數據庫了來讀該列表了,當然,也有人會問,如果在這5分鐘內某條新聞刪除了或修改了怎么辦,沒關系,我們在刪除或修改時可以根據cache key來強制刪除該cache項,當然,如果你覺得你對列表的時效性不是特別在意,你可以不強制刪除該cache項,讓cache項定義的時間點自動失效。當然,最好還是提供一個方法按匹配模式項來強行刪除cache項就可以了,例如:
1/**//// <summary>
2/// 刪除匹配的newssettopn列表的cache項
3/// </summary>
4public static void clearnewssettopncache(string language,string classcode,int topn)
5{
6 string cachekey = string.format("newssettopn-lg:{0}:cc:{1}:tn:{2}",language,classcode,topn.tostring());
7 sitecache.removebypattern(cachekey);
8}
9
發布新聞后調用靜態方法clearnewssettopncache()強行清除原來的topn緩存項,例如:
1/**//// <summary>
2/// 發布(新建)新聞
3/// </summary>
4/// <param name="post">新聞實例</param>
5/// <returns>返回狀態</returns>
6public static int create(news post)
7{
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}
that's all.若有不妥之處還望各位同行指正。
新聞熱點
疑難解答
圖片精選