下面我就结合实际开发的应用跟大家分享一下使用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 }102103 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 }115116 public static void resetfactor(int cachefactor)117 {118 factor = cachefactor;119 }120121122123 }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}