zl程序教程

您现在的位置是:首页 >  后端

当前栏目

详解Winform里面的缓存使用

Winform缓存 使用 详解 里面
2023-06-13 09:15:16 时间

缓存在很多情况下需要用到,合理利用缓存可以一方面可以提高程序的响应速度,同时可以减少对特定资源访问的压力。本文主要针对自己在Winform方面的缓存使用做一个引导性的介绍,希望大家能够从中了解一些缓存的使用场景和使用方法。缓存是一个中大型系统所必须考虑的问题。为了避免每次请求都去访问后台的资源(例如数据库),我们一般会考虑将一些更新不是很频繁的,可以重用的数据,通过一定的方式临时地保存起来,后续的请求根据情况可以直接访问这些保存起来的数据。这种机制就是所谓的缓存机制。

.NET4.0的缓存功能主要由三部分组成:System.Runtime.Caching,System.Web.Caching.Cache和OutputCache。

System.Runtime.Caching这是在.NET4.0中新增的缓存框架,主要是使用MemoryCache对象,该对象存在于程序集System.Runtime.Caching.dll。

System.Web.Caching.Cache这个则是在.NET2.0开始就一直存在的缓存对象,一般主要用在Web中,当然也可以用于Winform里面,不过要引用System.Web.dll。

OutputCache则是Asp.NET里面使用的,在ASP.NET4.0之前的版本都是直接使用System.Web.Caching.Cache来缓存HTML片段。在ASP.NET4.0中对它进行了重新设计,提供了一个OutputCacheProvider供开发人员进行扩展,但是它默认情况下,仍然使用System.Web.Caching.Cache来做做缓存。

1、自定义Hastable的缓存处理。
除了上面三种的缓存机制,一般我们还可以在静态对象里面通过HashTable或者Dictionary的方式进行自定义的缓存存储和使用。

例如我在我自己所开发的程序里面,都使用了工厂类来创建业务对象,由于创建业务对象以及数据访问层对象,是一个在界面或者中间层反复调用的操作,因此需要把经常调用的对象把它存储起来,下载调用的时候,直接从内存中取出来即可。如下面的BLLFactory类,就是一个基于泛型对象的业务类的创建操作,使用了基于Hashtable的静态对象进行缓存处理。

复制代码代码如下:


///<summary>
   ///对业务类进行构造的工厂类
   ///</summary>
   ///<typeparamname="T">业务对象类型</typeparam>
   publicclassBLLFactory<T>whereT:class
   {
       privatestaticHashtableobjCache=newHashtable();
       privatestaticobjectsyncRoot=newObject();

       ///<summary>
       ///创建或者从缓存中获取对应业务类的实例
       ///</summary>
       publicstaticTInstance
       {
           get
           {
               stringCacheKey=typeof(T).FullName;
               Tbll=(T)objCache[CacheKey]; //从缓存读取 
               if(bll==null)
               {
                   lock(syncRoot)
                   {
                       if(bll==null)
                       {
                           bll=Reflect<T>.Create(typeof(T).FullName,typeof(T).Assembly.GetName().Name);//反射创建,并缓存
                           objCache.Add(typeof(T).FullName,bll);
                       }
                   }
               }
               returnbll;
           }
       }
   }

2、使用.NET4.0的MemoryCache对象实现缓存

MemoryCache的使用网上介绍的不多,不过这个是.NET4.0新引入的缓存对象,估计主要是替换原来企业库的缓存模块,使得.NET的缓存可以无处不在,而不用基于特定的Windows版本上使用。

首先我们使用来创建一个基于MemoryCache的辅助类MemoryCacheHelper,方便调用进行缓存处理。

复制代码代码如下:


///<summary>
   ///基于MemoryCache的缓存辅助类
   ///</summary>
   publicstaticclassMemoryCacheHelper
   {
       privatestaticreadonlyObject_locker=newobject();

       publicstaticTGetCacheItem<T>(Stringkey,Func<T>cachePopulate,TimeSpan?slidingExpiration=null,DateTime?absoluteExpiration=null)
       {
           if(String.IsNullOrWhiteSpace(key))thrownewArgumentException("Invalidcachekey");
           if(cachePopulate==null)thrownewArgumentNullException("cachePopulate");
           if(slidingExpiration==null&&absoluteExpiration==null)thrownewArgumentException("Eitheraslidingexpirationorabsolutemustbeprovided");

           if(MemoryCache.Default[key]==null)
           {
               lock(_locker)
               {
                   if(MemoryCache.Default[key]==null)
                   {
                       varitem=newCacheItem(key,cachePopulate());
                       varpolicy=CreatePolicy(slidingExpiration,absoluteExpiration);

                       MemoryCache.Default.Add(item,policy);
                   }
               }
           }

           return(T)MemoryCache.Default[key];
       }

       privatestaticCacheItemPolicyCreatePolicy(TimeSpan?slidingExpiration,DateTime?absoluteExpiration)
       {
           varpolicy=newCacheItemPolicy();

           if(absoluteExpiration.HasValue)
           {
               policy.AbsoluteExpiration=absoluteExpiration.Value;
           }
           elseif(slidingExpiration.HasValue)
           {
               policy.SlidingExpiration=slidingExpiration.Value;
           }

           policy.Priority=CacheItemPriority.Default;

           returnpolicy;
       }
   }

这个辅助类只有一个public方法,就是GetCacheItem,使用的时候,需要指定key和获取数据的处理代理,还有缓存的过期时间,是基于TimeSpan的还是基于绝对时间的,选择其一。

上面的辅助类,我们在什么情况下会使用到呢?

假如在一个工作流模块中用到了人员ID,而人员ID需要进行人员名称的转义,人员信息我们一般知道放在权限系统模块里面,那么如果在工作流里面需要频繁对人员ID进行转义,那么就需要方法调用权限系统的接口模块,这样处理就可以使用缓存模块进行优化处理的了。

复制代码代码如下:
voidgridView1_CustomColumnDisplayText(objectsender,DevExpress.XtraGrid.Views.Base.CustomColumnDisplayTextEventArgse)
       {
           if(e.Column.FieldName.Equals("ProcUser")||e.Column.FieldName.Equals("ProcUid")||e.Column.FieldName.Equals("UserId"))
           {
               if(e.Value!=null)
               {
                   e.DisplayText=SecurityHelper.GetUserFullName(e.Value.ToString());
               }
           }
       }

其中的SecurityHelper.GetUserFullName是我对调用进行基于缓存的二次封装,具体逻辑如下所示。

复制代码代码如下:
///<summary>
       ///根据用户的ID,获取用户的全名,并放到缓存里面
       ///</summary>
       ///<paramname="userId">用户的ID</param>
       ///<returns></returns>
       publicstaticstringGetUserFullName(stringuserId)
       {           
           stringkey="Security_UserFullName"+userId;
           stringfullName=MemoryCacheHelper.GetCacheItem<string>(key,
               delegate(){returnBLLFactory<User>.Instance.GetFullNameByID(userId.ToInt32());},
               newTimeSpan(0,30,0));//30分钟过期
           returnfullName;
       }

MemoryCacheHelper的方法GetCacheItem里面的Func<T>我使用了一个匿名函数用来获取缓存的值。

复制代码代码如下:
delegate(){returnBLLFactory<User>.Instance.GetFullNameByID(userId.ToInt32());}

而调用BLLFactory<User>.Instance.GetFullNameByID则是从数据库里面获取对应的数据了。

这样在第一次或者缓存过期的时候,自动调用业务对象类的方法来获取数据了。

最后,在界面上调用GetUserFullName的方法即可实现基于缓存方式的调用,程序第一次使用的,碰到指定的键没有数据,就去数据库里面获取,以后碰到该键,则直接获取缓存的数据了。

下面图形是程序具体的实现效果。

当然,以上两种方式都还可以通过AOP的注入方式实现代码的简化操作,不过由于对AOP的引入,会涉及到更多的知识点,而且熟悉程序还不够,所以依然采用较为常用的方式来处理缓存的数据。