缓存机制理解及C#开发使用
随着Web的迅猛发展,从1.0、2.0再到现在的3.0无论是硬件还是软件对它的支持都是巨大的,这个过程中很多IT大佬提出了非常牛的定律,像摩尔定律、吉尔德定律、麦特卡尔定律、贝尔定律等,整个IT的发展也是按照这4大定律的驱使,像这个摩尔定律和贝尔定律大体是说我们用到的像电脑等硬件每18个月性能就会提高一倍,也就是说18个月前你花6000买的电脑现在3000就能买到同样配置的,吉尔德定律和麦特卡尔定律是说我们现在用到的宽带会越来越不值钱,可能以后会免费,后续那些牛的企业或人都是利用宽带的IT精英们,这个确实是这样的,像我们这些做软件开发的谁能离开网络?在这个过程中我所理解的web也从最简单的HTML进化到富客户端,然后到插件化、信息发布、服务的方式,这个过程中产生了很多新技术,AJAX、Flash\Silverligth\Flex、REST\WebService、微件(Widgets)、WebCache、静态化等,这些新技术也是伴随着硬件的提升而产生的,像我今天探讨的这个WebCache就是硬件的提升带来的,WebCache我们最直观的理解就是页面缓存,是放在内存中的,像6年前那时候咱们的电脑或普通服务器的内存都不会超过1G,所以说即使有这个技术也不会在国内流行起来,而现在就不一样了,我们随便配置个笔记本现在标配内存都是8个G,不好好利用一下才怪呢,我们的系统从内存中读取数据的速度比从硬盘中读取不是一个等量级的,那是相当的快,所以缓存就随着而来,最近我做的几个大型的BS网站都用到了它,它的确好用,能提高网站的整体性能,提高访问速度,减少数据库的连接数和性能损耗,这里我们就从缓存的概念、使用场景、asp.net开发中如何应用缓存、缓存的技术特点等4方面去深入了解它。
通常的了解是我们的应用程序可以将那些频繁访问的数据,以及那些需要大量处理时间来创建的数据存储在内存中,从而提高性能,这就是页面缓存的通俗理解,它主要包括应用程序缓存和页输出缓存,应用程序缓存提供了一种编程方式,可通过键/值对将任意数据存储在内存中,页输出缓存则是在内存中存储处理后的 ASP.NET 页的内容。
缓存的使用场景主要总结了3个方面,一是研发模块比较稳定,研发模块比较稳定,读取数据比较频繁,更新数据频率低;二是历史数据查询、报表统计等;三是部分页面级缓存(像自定义控件)。
理解了页面缓存的概念之后,我们就可以用简单的编码例子去帮助理解了,首先我们可以对asp.net的缓存System.Web.Caching.Cache进行一下封装,主要是对微软提供的缓存进行操作,这里我们用设计模式的理念出发,我们是面向接口编程的,接口名称为公共缓存策略接口ICacheStrategy,主要对方法进行规范包括增、删、改、查、过期等,见如下代码:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Web.Caching; namespace FrameWork { /// <summary> /// 公共缓存策略接口 /// </summary> public interface ICacheStrategy { /// <summary> /// 添加指定ID的对象 /// </summary> /// <param name="objId"></param> /// <param name="o"></param> void AddObject(string objID, object o); /// <summary> /// 添加指定ID的对象 /// </summary> /// <param name="objId"></param> /// <param name="o"></param> /// <param name="timeOut">过期时间</param> void AddObject(string objId, object o, int timeOut); /// <summary> /// 添加指定ID的对象(关联指定文件组) /// </summaryICacheStrategy /// <param name="objId"></param> /// <param name="o"></param> /// <param name="files"></param> void AddObjectWithFileChange(string objId, object o, params string[] files); /// <summary> /// 添加指定ID的对象(关联指定文件组) /// </summaryICacheStrategy /// <param name="objId"></param> /// <param name="o"></param> /// <param name="files"></param> void AddObjectWithFileChange(string objId, object o, CacheItemRemovedCallback callback, params string[] files); /// <summary> /// 添加指定ID的对象(关联指定键值组) /// </summary> /// <param name="objId"></param> /// <param name="o"></param> /// <param name="dependKey"></param> void AddObjectWithDepend(string objId, object o, params string[] dependKey); /// <summary> /// 移除指定ID的对象 /// </summary> /// <param name="objId"></param> void RemoveObject(string objId); /// <summary> /// 返回指定ID的对象 /// </summary> /// <param name="objId"></param> /// <returns></returns> object RetrieveObject(string objId); /// <summary> /// 返回指定ID的对象 /// </summary> /// <param name="objId"></param> /// <returns></returns> T RetrieveObject<T>(string objId); /// <summary> /// 到期时间,单位:秒 /// </summary> int TimeOut { set; get; } } }
接口定义了之后,我们建一个默认缓存管理类DefaultCacheStrategy去实现这个接口,这里我们可以用单例模式,让这个缓存类在整个应用中只有一个实例,见代码如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Web.Caching; namespace FrameWork { /// <summary> /// 默认缓存管理类 /// </summary> public class DefaultCacheStrategy : ICacheStrategy { private static readonly DefaultCacheStrategy instance = new DefaultCacheStrategy(); protected static volatile System.Web.Caching.Cache webCache = System.Web.HttpRuntime.Cache; /// <summary> /// 默认缓存存活期为3600秒(1小时) /// </summary> protected int _timeOut = 3600; static DefaultCacheStrategy() { } /// <summary> /// 设置到期相对时间[单位: 秒] /// </summary> public virtual int TimeOut { set {_timeOut=value>0?value:3600;} get{return _timeOut>0?_timeOut:3600;} } /// <summary> /// 获取当前应用程序的 System.Web.Caching.Cache /// </summary> public static System.Web.Caching.Cache GetWebCacheObj { get { return webCache; } } public virtual void AddObject(string objId, object o) { if (objId == null || objId.Length == 0 || o == null) { return; } CacheItemRemovedCallback callBack = new CacheItemRemovedCallback(onRemove); if (TimeOut == 7200) { webCache.Insert(objId, o, null, DateTime.MaxValue, TimeSpan.Zero, System.Web.Caching.CacheItemPriority.High, callBack); } else { webCache.Insert(objId, o, null, DateTime.Now.AddSeconds(TimeOut), System.Web.Caching.Cache.NoSlidingExpiration, System.Web.Caching.CacheItemPriority.High, callBack); } } /// <summary> /// 加入当前对象到缓存中 /// </summary> /// <param name="objId">对象的键值</param> /// <param name="o">缓存的对象</param> public virtual void AddObjectWith(string objId, object o) { if (objId == null || objId.Length == 0 || o == null) { return; } CacheItemRemovedCallback callBack = new CacheItemRemovedCallback(onRemove); webCache.Insert(objId, o, null, System.DateTime.Now.AddSeconds(TimeOut), System.Web.Caching.Cache.NoSlidingExpiration, System.Web.Caching.CacheItemPriority.High, callBack); } /// <summary> /// 加入当前对象到缓存中,并对相关文件建立依赖 /// </summary> /// <param name="objId">对象的键值</param> /// <param name="o">缓存的对象</param> /// <param name="files">监视的路径文件</param> public virtual void AddObjectWithFileChange(string objId, object o, params string[] files) { if (objId == null || objId.Length == 0 || o == null) { return; } CacheItemRemovedCallback callBack = new CacheItemRemovedCallback(onRemove); CacheDependency dep = new CacheDependency(files, DateTime.Now); webCache.Insert(objId, o, dep, System.DateTime.Now.AddSeconds(TimeOut), System.Web.Caching.Cache.NoSlidingExpiration, System.Web.Caching.CacheItemPriority.High, callBack); } /// <summary> /// 加入当前对象到缓存中,并对相关文件建立依赖 /// </summary> /// <param name="objId">对象的键值</param> /// <param name="o">缓存的对象</param> /// <param name="files">监视的路径文件</param> public virtual void AddObjectWithFileChange(string objId, object o, CacheItemRemovedCallback callback, params string[] files) { if (objId == null || objId.Length == 0 || o == null) { return; } CacheDependency dep = new CacheDependency(files, DateTime.Now); webCache.Insert(objId, o, dep, System.DateTime.Now.AddSeconds(TimeOut), System.Web.Caching.Cache.NoSlidingExpiration, System.Web.Caching.CacheItemPriority.High, callback); } /// <summary> /// 加入当前对象到缓存中,并使用依赖键 /// </summary> /// <param name="objId">对象的键值</param> /// <param name="o">缓存的对象</param> /// <param name="dependKey">依赖关联的键值</param> public virtual void AddObjectWithDepend(string objId, object o, params string[] dependKey) { if (objId == null || objId.Length == 0 || o == null) { return; } CacheItemRemovedCallback callBack = new CacheItemRemovedCallback(onRemove); CacheDependency dep = new CacheDependency(null, dependKey, DateTime.Now); webCache.Insert(objId, o, dep, System.DateTime.Now.AddSeconds(TimeOut), System.Web.Caching.Cache.NoSlidingExpiration, System.Web.Caching.CacheItemPriority.High, callBack); } public void onRemove(string key, object value, CacheItemRemovedReason reason) { switch (reason) { case CacheItemRemovedReason.DependencyChanged: break; case CacheItemRemovedReason.Expired: { //CacheItemRemovedCallback callBack = new CacheItemRemovedCallback(this.onRemove); //webCache.Insert(key, val, null, System.DateTime.Now.AddMinutes(TimeOut), // System.Web.Caching.Cache.NoSlidingExpiration, // System.Web.Caching.CacheItemPriority.High, // callBack); break; } case CacheItemRemovedReason.Removed: { break; } case CacheItemRemovedReason.Underused: { break; } default: break; } } /// <summary> /// 删除缓存对象 /// </summary> /// <param name="objId">对象的关键字</param> public virtual void RemoveObject(string objId) { if (objId == null || objId.Length == 0) { return; } webCache.Remove(objId); } /// <summary> /// 返回一个指定的对象 /// </summary> /// <param name="objId">对象的关键字</param> /// <returns>对象</returns> public virtual object RetrieveObject(string objId) { if (objId == null || objId.Length == 0) { return null; } return webCache.Get(objId); } /// <summary> /// 返回指定ID的对象 /// </summary> /// <param name="objId"></param> /// <typeparam name="T">返回数据的类型</typeparam> /// <returns></returns> public virtual T RetrieveObject<T>(string objId) { object o = RetrieveObject(objId); return o != null ? (T)o : default(T); } public void AddObject(string objId, object o, int timeOut) { if (String.IsNullOrEmpty(objId) || String.IsNullOrEmpty(objId.Trim())) return; CacheItemRemovedCallback callBack = new CacheItemRemovedCallback(onRemove); if (timeOut > 0) { webCache.Insert(objId, o, null, DateTime.Now.AddMilliseconds(timeOut), System.Web.Caching.Cache.NoSlidingExpiration, System.Web.Caching.CacheItemPriority.High, callBack); } else { webCache.Insert(objId, o, null, DateTime.MaxValue, TimeSpan.Zero, System.Web.Caching.CacheItemPriority.High, callBack); } } } }
这个类主要是对System.Web.Caching.Cache webCache这个实际的缓存进行封装的,我们封装出来之后一是为了方便使用,另外就是为了研发的规范性,避免了研发人员自行对微软自己的缓存进行研究及调用,页面调用参考代码:
DefaultCacheStrategy dcs = new DefaultCacheStrategy(); dcs.AddObject("1111", "缓存的实际内容"); this.lblTest.Text = dcs.RetrieveObject<string>("1111");
讲完了缓存的开发方式,我们可以总结一下缓存的技术特点了,我总结有4条:一是减少数据库的访问次数;二是提高应用的性能;三是增强用户的体验;四是提高应用的访问速度。