• 利用委托实现自己的数据缓存仓库(附上Demo)


    Demo源码

    写在前面的话

      写完这篇博客后,总觉得少了些什么,后来想了下,感觉自己只是把结果给亮了出来,自己为什么想到这么做,这个类库出生的缘由未详述,因此,在本段作下说明,如有不足之处,希望能和大家一起交流沟通。。,大家共同提高啊!

      我的想法很简单,我在拥有:

    1. 获取数据的方法

      并面对了下面的场景:

    1. 数据仅从数据库读取,不在程序中被修改
    2. 获取数据的方法在程序的很多地方被频繁的调用
    3. 我能把控数据的准确性对程序的影响

      我希望:可以有一个容器,让我在程序的入口处进行数据的初始化(丢给它获取数据的方法、key、过期时间)后,我能够在程序中其它任何地方通过key来获取到数据,并且,数据能够根据我设定的过期时间进行有效地更新!

      以此来达到:

    1. 缓存直接和方法进行绑定,而并非直接将具体值丢入缓存
    2. 避免在不同的页面声明相同的静态变量来获取相同的数据,减少代码量
    3. 统一在程序的入口管理所有的全局变量,提高代码的可维护性
    4. 避免频繁读取数据库,提高应用程序的性能

    背景

      本来想聊聊本文产生的背景的,后来发现本码农词穷了。因此,直入主题,本文的工作是利用委托实现了一个全局的数据缓存仓库。

      这个类库接收4个参数:1 您要存储的数据的数据类型 2 获取需要存储数据的方法 3 过期的时间 4 读取该数据的唯一key

      这个类库就能够:根据key获取数据,数据通过执行您传入的获取数据的方法来获得,当上一次获取的时间过期后,会重新执行获取数据的方法以更新数据!

      推荐的使用方式:1 在应用程序的开端,进行所有需要缓存数据的初始化操作,统一管理所有的key;这样可以避免不必要的混乱

              2 在应用程序中需要使用的地方,直接通过key进行数据的获取,这样避免了在每个页面中写重复的代码,提高应用的效率

    实现

      第一步,我们为需要存储的数据定义一个标准的数据结构:

      

        /// <summary>
        /// 存储的数据结构
        /// </summary>
        /// <typeparam name="T">需要存储的数据的数据类型(string int ..)</typeparam>
        public sealed class StoredDataInfo<T>
        {
    
            /// <summary>
            /// 存储的数据
            /// </summary>
            public T Data { get; set; }
    
            /// <summary>
            /// 获取需要存储的数据的方法
            /// </summary>
            public Func<T> GetDataMethod { get; set; }
    
            /// <summary>
            /// 数据过期的时间
            /// </summary>
            public int TimeOfDuration { get; set; }
    
            /// <summary>
            /// 数据上一次被更新的时间
            /// </summary>
            public DateTime LastModifyTime { get; set; }
    
        }

      以上代码一目了然,不用多说,大家都懂得。

      第二步,我们需要一个列表来存储需要的数据,因为我们会存储很多的数据

      

            //存储所有数据
            /// <summary>
            /// 存储所有数据
            /// </summary>
            private static readonly Dictionary<string, StoredDataInfo<T>> EntireStoredData = new Dictionary<string, StoredDataInfo<T>>();

      第三步,一个初始化数据的方法

            //初始化数据项
            /// <summary>
            /// 初始化数据项
            /// </summary>
            /// <param name="key"></param>
            /// <param name="storedData"></param>
            private static string InitStoredDataItem(string key, StoredDataInfo<T> storedData)
            {
                lock (lockObj)
                {
                    if (EntireStoredData.ContainsKey(key))
                    {
                        return "key:" + key + " 已存在";
                    }
                    EntireStoredData.Add(key, storedData);
                }
                return "";
            }

      第四步,根据key获取数据项的方法

            // 获取指定key的数据项
            /// <summary>
            /// 获取指定key的数据项
            /// </summary>
            /// <param name="key"></param>
            /// <param name="isForcedRefresh">是否强制更新</param>
            /// <returns></returns>
            public static T GetData(string key, bool isForcedRefresh = false)
            {
                //不存在key
                if (!HasKey(key))
                {
                    #region
    
                    string currKeys = "";
                    string currTType = "";
                    if (EntireStoredData.Any())
                    {
                        currKeys = string.Join(",", EntireStoredData.Keys.ToArray());
                        var v = EntireStoredData.First().Value.Data;
                        currTType = v.GetType().ToString();
                    }
                    throw new Exception(string.Format("无指定key:{0},当前池包含key集合{1},当前池类型:{2}", key, currKeys, currTType));
    
                    #endregion
                }
    
                //根据key获取value
                StoredDataInfo<T> sdi = EntireStoredData[key];
    
                //判断是否过期
                int timeOfDuration = sdi.TimeOfDuration;
                DateTime lastModifyTime = sdi.LastModifyTime;
    
                if (!isForcedRefresh && DateTime.Now.AddMinutes(-timeOfDuration) <= lastModifyTime)
                    return sdi.Data;
    
                //重新更新数据
                sdi.Data = sdi.GetDataMethod();
                sdi.LastModifyTime = DateTime.Now;
    
                return sdi.Data;
            }

    使用

            static void Main(string[] args)
            {
                #region 数据缓存仓库测试
    
                //key
                const string key = "GetCurrDateKey";
                //初始化仓库
                DataWarehouse<string>.InitDataItem(key, GetCurrDate, 1);
    
                //根据key获取值
                Console.WriteLine(DataWarehouse<string>.GetData(key));
                //休眠 等待过期
                Thread.Sleep(1000 * 61);
                //再次根据key获取值
                Console.WriteLine(DataWarehouse<string>.GetData(key));
    
                Console.ReadLine();
    
                #endregion
            }
    
            /// <summary>
            /// 获取时间
            /// </summary>
            /// <returns></returns>
            private static string GetCurrDate()
            {
                return DateTime.Now.ToString();
            }

      以上,做了一个很小的测试,存储一个当前时间的string类型的值,设定过期时间为1分钟,结果很显而易见。

      

  • 相关阅读:
    SQLServer: 解决“错误15023:当前数据库中已存在用户或角色
    DEV界面皮肤
    模拟业务最小测试用例
    POJ 2503 Babelfish(map)
    POJ 2001 Shortest Prefixes
    洛谷 P2672 推销员
    POJ 2104 K-th Number && 洛谷 P3834 【模板】可持久化线段树 1(主席树)
    洛谷 P1589 泥泞路
    HDU 6183 Color it(动态开点线段树)
    POJ 2482 Stars in Your Window
  • 原文地址:https://www.cnblogs.com/SmallZL/p/4007128.html
Copyright © 2020-2023  润新知