zoukankan      html  css  js  c++  java
  • Winform里面的缓存,MemoryCache使用

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

    .NET 4.0的缓存功能主要由三部分组成:System.Runtime.Caching,System.Web.Caching.Cache和Output Cache。

    MemoryCache对象:这是在.NET 4.0中新增的缓存框架,在Namespace:System.Runtime.Caching ,Assembly:System.Runtime.Caching.dll中

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

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

    1、自定义Hastable的缓存处理。

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

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

    复制代码
        /// <summary>
        /// 对业务类进行构造的工厂类
        /// </summary>
        /// <typeparam name="T">业务对象类型</typeparam>
        public class BLLFactory<T> where T : class
        {
            private static Hashtable objCache = new Hashtable();
            private static object syncRoot = new Object();
    
            /// <summary>
            /// 创建或者从缓存中获取对应业务类的实例
            /// </summary>
            public static T Instance
            {
                get
                {
                    string CacheKey = typeof(T).FullName;
                    T bll = (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);
                            }
                        }
                    }
                    return bll;
                }
            }
        } 
    复制代码

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

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

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

    复制代码
        /// <summary>
        /// 基于MemoryCache的缓存辅助类
        /// </summary>
        public static class MemoryCacheHelper
        {
            private static readonly Object _locker = new object();
         
            public static T GetCacheItem<T>(String key, Func<T> cachePopulate, TimeSpan? slidingExpiration = null, DateTime? absoluteExpiration = null)
            {
                if(String.IsNullOrWhiteSpace(key)) throw new ArgumentException("Invalid cache key");
                if(cachePopulate == null) throw new ArgumentNullException("cachePopulate");
                if(slidingExpiration == null && absoluteExpiration == null) throw new ArgumentException("Either a sliding expiration or absolute must be provided");
         
                if(MemoryCache.Default[key] == null)
                {
                    lock(_locker)
                    {
                        if(MemoryCache.Default[key] == null)
                        {
                            var item = new CacheItem(key, cachePopulate());
                            var policy = CreatePolicy(slidingExpiration, absoluteExpiration);
         
                            MemoryCache.Default.Add(item, policy);
                        }
                    }
                }
         
                return (T)MemoryCache.Default[key];
            }
         
            private static CacheItemPolicy CreatePolicy(TimeSpan? slidingExpiration, DateTime? absoluteExpiration)
            {
                var policy = new CacheItemPolicy();
         
                if(absoluteExpiration.HasValue)
                {
                    policy.AbsoluteExpiration = absoluteExpiration.Value;
                }
                else if(slidingExpiration.HasValue)
                {
                    policy.SlidingExpiration = slidingExpiration.Value;
                }
         
                policy.Priority = CacheItemPriority.Default;
         
                return policy;
            }
        }
    复制代码

    下面在给个经过改良的版本,供参考吧!

        /// <summary>
        /// 基于System.Runtime.Caching.dll中的MemoryCache的缓存辅助类
        /// </summary>
        public static class MemoryCacheHelper
        {
            
            private static readonly Object _locker = new object();
    
            /// <summary>
            /// 如果缓存中存在指定的key,则优先从缓存中返回
            /// </summary>
            /// <typeparam name="T">返回值类型</typeparam>
            /// <param name="key">缓存关键字</param>
            /// <param name="cachePopulate">需要执行的方法、Lambda表达式、(匿名)代理等。
            /// <code>例如:() => "测试",  或者 
            /// delegate () { return new aaa("测试"); },
            /// </code>
            /// </param>
            /// <param name="slidingExpiration">滑动窗口模式的使用过期时间</param>
            /// <param name="absoluteExpiration">绝对过期时间</param>
            /// <returns></returns>
            public static T GetCacheItem<T>(String key, Func<T> cachePopulate, TimeSpan? slidingExpiration = null, DateTime? absoluteExpiration = null)
            {
                if (String.IsNullOrWhiteSpace(key)) throw new ArgumentException("Invalid cache key");
                if (cachePopulate == null) throw new ArgumentNullException("cachePopulate");
                if (slidingExpiration == null && absoluteExpiration == null) throw new ArgumentException("Either a sliding expiration or absolute must be provided");
    
                if (MemoryCache.Default[key] == null)
                {
                    lock (_locker)
                    {
                        if (MemoryCache.Default[key] == null)
                        {
                            var item = new CacheItem(key, cachePopulate());
                            var policy = CreatePolicy(slidingExpiration, absoluteExpiration);
    
                            MemoryCache.Default.Add(item, policy);
                        }
                    }
                }
    
                return (T)((MemoryCache.Default[key] is T) ? MemoryCache.Default[key] : default(T));
                //return (T)MemoryCache.Default[key];
            }
    
    
            /// <summary>
            /// 如果缓存中存在指定的key,则优先从缓存中返回
            /// </summary>
            /// <typeparam name="T">返回值类型</typeparam>
            /// <param name="key">缓存关键字</param>
            /// <param name="cachePopulate">需要执行的方法、Lambda表达式、(匿名)代理等。
            /// <code>例如:() => "测试",  或者 
            /// delegate () { return new aaa("测试"); },
            /// </code>
            /// </param>
            /// <param name="expirationTime">缓存过期时间</param>
            /// <param name="expirationTimeType">缓存过期时间类型</param>
            /// <param name="enabledCache">是否启用缓存,如果false则每次都是直接执行被调方法cachePopulate,默认启用,</param>
            /// <returns></returns>
            public static T GetCacheItem<T>(String key, Func<T> cachePopulate, TimeSpan expirationTime, ExpirationTimeType expirationTimeType, bool enabledCache = true)
            {
                if (String.IsNullOrWhiteSpace(key)) throw new ArgumentException("Invalid cache key");
                if (cachePopulate == null) throw new ArgumentNullException("cachePopulate");
                if (expirationTime == null) throw new ArgumentException("Either a sliding expiration must be provided");
    
                T tmp = default(T);
    
                if (enabledCache)
                {
                    if (MemoryCache.Default[key] == null)
                    {
                        lock (_locker)
                        {
                            if (MemoryCache.Default[key] == null)
                            {
                                Console.WriteLine("MemoryCache is null.");
                                CacheItem item = new CacheItem(key, cachePopulate());
    
                                CacheItemPolicy policy = null;
                                if (expirationTimeType == ExpirationTimeType.AbsoluteExpirationTimeType)
                                    policy = CreatePolicy(null, DateTime.Now.Add(expirationTime));
                                else if (expirationTimeType == ExpirationTimeType.SlidingExpirationTimeType)
                                    policy = CreatePolicy(expirationTime, null);
                                else
                                    policy = CreatePolicy(TimeSpan.Zero, null);
    
                                MemoryCache.Default.Add(item, policy);
                            }
                        }
                    }
                    tmp = (MemoryCache.Default[key] is T) ? (T)MemoryCache.Default[key] : default(T);
                    //return (MemoryCache.Default[key] is T) ? (T)MemoryCache.Default[key] : default(T);
                    //return (T)MemoryCache.Default[key];
                }
                else
                {
                    tmp = cachePopulate();
                }
    
                return tmp;
            }
    
            
            /// <summary>
            /// 从缓存中移除知道键值的缓存对象
            /// </summary>
            /// <param name="key">缓存对象的键</param>
            /// <returns></returns>
            public static bool RemoveCacheItem(string key)
            {
                bool isRemove = false;
                try
                {
                    if (MemoryCache.Default[key] != null)
                    {
                        lock (_locker)
                        {
                            if (MemoryCache.Default[key] != null)
                            {
                                MemoryCache.Default.Remove(key);
                            }
                        }
                    }
                    isRemove = true;
                }
                catch (Exception ex)
                {
                    throw ex;
                }
    
                return isRemove;
            }
    
            
            /// <summary>
            /// 构造缓存过期时间和优先级
            /// </summary>
            /// <param name="slidingExpiration">滑动窗口模式的使用过期时间</param>
            /// <param name="absoluteExpiration">绝对过期时间</param>
            /// <returns></returns>
            private static CacheItemPolicy CreatePolicy(TimeSpan? slidingExpiration, DateTime? absoluteExpiration)
            {
                if (slidingExpiration == null && absoluteExpiration == null)
                    throw new ArgumentException("Either a sliding expiration or absolute must be provided");
    
                CacheItemPolicy policy = new CacheItemPolicy();
    
                if (slidingExpiration.HasValue)
                {
                    policy.SlidingExpiration = slidingExpiration.Value;
                }
                else if (absoluteExpiration.HasValue)
                {
                    policy.AbsoluteExpiration = absoluteExpiration.Value;
                }
                policy.Priority = CacheItemPriority.Default;
    
                //List<string> filePaths = new List<string>();
                //filePaths.Add("c:\cache\example.txt");
                //policy.ChangeMonitors.Add(new HostFileChangeMonitor(filePaths));
    
                return policy;
            }
    
            
            /// <summary>
            /// 缓存过期时间类型
            /// </summary>
            public enum ExpirationTimeType
            {
                /// <summary>
                /// 滑动窗口模式的使用过期时间
                /// </summary>
                SlidingExpirationTimeType = 1,
    
                /// <summary>
                /// 绝对过期时间
                /// </summary>
                AbsoluteExpirationTimeType = 2
            }
    
    
        }
    View Code

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

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

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

    复制代码
            void gridView1_CustomColumnDisplayText(object sender, DevExpress.XtraGrid.Views.Base.CustomColumnDisplayTextEventArgs e)
            {
                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>
            /// <param name="userId">用户的ID</param>
            /// <returns></returns>
            public static string GetUserFullName(string userId)
            {            
                string key = "Security_UserFullName" + userId;
                string fullName = MemoryCacheHelper.GetCacheItem<string>(key,
                    delegate() { return BLLFactory<User>.Instance.GetFullNameByID(userId.ToInt32()); },
                    new TimeSpan(0, 30, 0));//30分钟过期
                return fullName;
            }
    复制代码

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

    delegate() { return BLLFactory<User>.Instance.GetFullNameByID(userId.ToInt32()); }

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

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

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

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

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

    出处:https://www.cnblogs.com/wuhuacong/p/3526335.html

    ======================================================================================

    摘要

    在对winform做的项目优化的时候,首先想到的是对查询,并不经常变化的数据进行缓存,但对web项目来说有System.Web.Caching.Cache类进行缓存,那么winform端该如何呢?你可能会想到,存到文件中,但那可能有问题,文件操作权限问题,IO操作性能问题。

    解决办法

    针对exe的项目,可以使用MemoryCache这个类,进行内存级别的缓存。

    辅助类

    复制代码
        /// <summary>
        /// 基于MemoryCache的缓存辅助类
        /// </summary>
        public static class MemoryCacheHelper
        {
            private static readonly Object _locker = new object();
    
            public static T FindCacheItem<T>(string key, Func<T> cachePopulate, TimeSpan? slidingExpiration = null,
    DateTime? absoluteExpiration = null) { if (String.IsNullOrWhiteSpace(key)) { throw new ArgumentException("Invalid cache key"); } if (cachePopulate == null) { throw new ArgumentNullException("cachePopulate"); } if (slidingExpiration == null && absoluteExpiration == null) { throw new ArgumentException("Either a sliding expiration or absolute must be provided"); } if (MemoryCache.Default[key] == null) { lock (_locker) { if (MemoryCache.Default[key] == null) { var item = new CacheItem(key, cachePopulate()); var policy = CreatePolicy(slidingExpiration, absoluteExpiration); MemoryCache.Default.Add(item, policy); } } } return (T)MemoryCache.Default[key]; } /// <summary> /// 移除缓存 /// </summary> /// <param name="key"></param> public static void RemoveCache(string key) { MemoryCache.Default.Remove(key); } private static CacheItemPolicy CreatePolicy(TimeSpan? slidingExpiration, DateTime? absoluteExpiration) { var policy = new CacheItemPolicy(); if (absoluteExpiration.HasValue) { policy.AbsoluteExpiration = absoluteExpiration.Value; } else if (slidingExpiration.HasValue) { policy.SlidingExpiration = slidingExpiration.Value; } policy.Priority = CacheItemPriority.Default; return policy; } }
    复制代码

    测试

    复制代码
      class Program
        {
            static void Main(string[] args)
            {
                string cacheKey = "person_key";
                Person p = MemoryCacheHelper.FindCacheItem<Person>(cacheKey,
                    () =>
                    {
                        return new Person() { Id = Guid.NewGuid(), Name = "wolfy" };
                    }, new TimeSpan(0, 30, 0));
                if (p != null)
                {
                    Console.WriteLine(p.ToString());
                }
                Console.WriteLine("获取缓存中数据");
                Person p2 = MemoryCacheHelper.FindCacheItem<Person>(cacheKey,
                    () =>
                    {
                        return new Person() { Id = Guid.NewGuid(), Name = "wolfy" };
                    }, new TimeSpan(0, 30, 0));
                if (p2 != null)
                {
                    Console.WriteLine(p2.ToString());
                }
                MemoryCacheHelper.RemoveCache(cacheKey);
                Person p3 = MemoryCacheHelper.FindCacheItem<Person>(cacheKey,
                   () =>
                   {
                       return new Person() { Id = Guid.NewGuid(), Name = "wolfy" };
                   }, new TimeSpan(0, 30, 0));
                if (p3 != null)
                {
                    Console.WriteLine(p3.ToString());
                }
                Console.Read();
            }
    
        }
        public class Person
        {
            public Guid Id { set; get; }
            public string Name { set; get; }
            public override string ToString()
            {
                return Id.ToString() + "	" + Name;
            }
        }
    复制代码

    参考:

    https://msdn.microsoft.com/en-us/library/system.runtime.caching.memorycache(v=vs.110).aspx

    出处:https://www.cnblogs.com/wolf-sun/p/7251343.html

  • 相关阅读:
    php 为什么new一个对象后面要加一个反斜杠
    c# 判断当前时间是否在某一时间段内
    关于Entity Framework的概念及搭建
    mvc 读写txt文档
    winform :DataGridView添加一列checkbox
    使用filter进行登录验证,并解决多次重定向问题
    关于Select选中问题
    错误:Parameter '0' not found.Available parameters are [arg1, arg0, param1, param2]的解决方法
    sql-省市区
    设置oracle主键自增长
  • 原文地址:https://www.cnblogs.com/mq0036/p/10312945.html
Copyright © 2011-2022 走看看