服务器本地缓存

1.简介

  服务器本地缓存是使用一个静态字典,根据唯一准确描述缓存的key来将值存入内存中

  新建一个CustomCache类,用来保存缓存

  代码如下:

using System;
using System.Collections.Generic;
namespace ceshi
{
    class CustomCache
    {
        private static Dictionary<string, object> CustomCacheDictionary = new Dictionary<string, object>();

        public static void Add(string key,object value)//添加缓存
        {
            CustomCacheDictionary.Add(key,value);
        }

        public static T GetT<T>(string key)//获取缓存的值
        {
            return (T)CustomCacheDictionary[key];
        }
        public static bool Exsits(string key)//判断缓存是否存在
        {
            return CustomCacheDictionary.ContainsKey(key);
        }
    }
}

  Program:

using System;
using System.Threading.Tasks;
using System.Threading;
namespace ceshi
{
    class Program
    {
        static void Main(string[] args)
        {
            for (int i = 0; i < 5; i++)
            {
                string key = "add_key_101";//唯一准确描述缓存的key
                int result;
                if (CustomCache.Exsits(key))
                {
                    result = CustomCache.GetT<int>(key);
                }
                else
                {
            //----------------调用模拟函数--------------- result = Simulation(); //----------------添加缓存-------------------
CustomCache.Add(key, result); } Console.WriteLine(result); } Console.Read(); } static int Simulation() { //-------------模拟获取数据的时耗-------------- int result; Thread.Sleep(2000); Random random = new Random(); result = random.Next(0, 100); return result; } } }

 

2.封装调用函数

  现实羡慕中缓存是无处不在的,所以为了方便使用缓存,可以将上面红色字体的代码封装到CustomCache里面,以方便调用

  CustomCache类添加一个函数:

using System;
using System.Collections.Generic;
namespace ceshi
{
    class CustomCache
    {
        private static Dictionary<string, object> CustomCacheDictionary = new Dictionary<string, object>();

        public static void Add(string key,object value)
        {
            CustomCacheDictionary.Add(key,value);
        }

        public static T GetT<T>(string key)
        {
            return (T)CustomCacheDictionary[key];
        }
        public static bool Exsits(string key)
        {
            return CustomCacheDictionary.ContainsKey(key);
        }
        public static T GetDataT<T>(string key,Func<T> func)//委托Func是无参有返回值
        {
            T result = default(T);
            if(Exsits(key))
            {
                result=(T)CustomCacheDictionary[key];
            }
            else
            {
                result=func.Invoke();//实例化外部模拟获取数据的函数,也就是运行这个函数并接收返回值
                Add(key, result);
            }
            return result;
        }
    }
}

  Program:

using System;
using System.Threading.Tasks;
using System.Threading;
namespace ceshi
{
    class Program
    {
        static void Main(string[] args)
        {
            for (int i = 0; i < 5; i++)
            {
                string key = "add_key_101";//唯一准确描述缓存的key
                int result;
                result=CustomCache.GetDataT<int>(key, () => Simulation());
                Console.WriteLine(result);
            }
            Console.Read();
        }

        static int Simulation()
        {
            //-------------模拟获取数据的时耗--------------
            int result;
            Thread.Sleep(2000);
            Random random = new Random();
            result = random.Next(0, 100);
            return result;
        }
    }
}

  这样在多次调用时可以节省很多代码量。

3.缓存进阶

  在缓存中,如果数据库的数据被修改了,缓存就可能产生脏数据

  所以应该使用一些方法,来及时清除更新这些脏数据

  1)更新的数据,影响一条缓存

    每次主动修改数据库时,根据key删除对应的缓存(为什么是删除不是更新呢,缓存一般不更新,删除之后再次访问会继续做缓存)

            CustomCacheDictionary.Remove(key);

  2)更新的数据,影响到多条缓存

    可以直接删除所有缓存,简单粗暴

            CustomCacheDictionary.Clear();

  3)跟新的数据,影响多条缓存,但这些缓存的key有大致相同的结构

    如,均以_customcategory为结尾

    这样我们可以根据条件删除缓存

using System;
using System.Collections.Generic;
namespace ceshi
{
    class CustomCache
    {
        private static Dictionary<string, object> CustomCacheDictionary = new Dictionary<string, object>();

        public static void Add(string key,object value)
        {
            CustomCacheDictionary.Add(key,value);
        }

        public static T GetT<T>(string key)
        {
            return (T)CustomCacheDictionary[key];
        }
        public static bool Exsits(string key)
        {
            return CustomCacheDictionary.ContainsKey(key);
        }
        public static T GetDataT<T>(string key,Func<T> func)//Func是无参有返回值
        {
            T result = default(T);
            if(Exsits(key))
            {
                result=(T)CustomCacheDictionary[key];
            }
            else
            {
                result=func.Invoke();
                Add(key, result);
            }
            return result;
        }

        public static void RemoveCondition(Func<string,bool> func)//根据条件删除缓存,委托为给一个string类型的参数,返回bool
        {
            List<string> keyList = new List<string>();
            foreach(string item in CustomCacheDictionary.Keys)
            {
                if(func.Invoke(item))
                {
                    keyList.Add(item);
                }
            }
            keyList.ForEach(key => CustomCacheDictionary.Remove(key));
        }
    }
}

  Program

using System;
using System.Threading.Tasks;
using System.Threading;
namespace ceshi
{
    class Program
    {
        static void Main(string[] args)
        {
            for (int i = 0; i < 4; i++)//添加四条以_customcategory为结尾的缓存
            {
                string key = $"add_key_10{i}_customcategory";//唯一准确描述缓存的key
                int result;
                result = CustomCache.GetDataT<int>(key, () => Simulation());
                Console.WriteLine(result);
            }


            {
                CustomCache.RemoveCondition((s) => s.EndsWith("_customcategory"));清除以_customcategory为结尾的缓存
            }

            Console.Read();
        }

        static int Simulation()
        {
            //-------------模拟获取数据的时耗--------------
            int result;
            Thread.Sleep(2000);
            Random random = new Random();
            result = random.Next(0, 100);
            return result;
        }
    }
}

  4)缓存过期

     在缓存中,我们基本需要加上过期时间,这样可以保证数据的可靠性

using System;
using System.Collections.Generic;
namespace ceshi
{
    class CustomCache
    {
        private static Dictionary<string, KeyValuePair<object, DateTime>> CustomCacheDictionary = new Dictionary<string, KeyValuePair<object, DateTime>>();

        public static void Add(string key, object value, int second = 3)//second定义数据过期时间,单位是秒
        {
            CustomCacheDictionary.Add(key, new KeyValuePair<object, DateTime>(value, DateTime.Now.AddSeconds(second)));
        }

        public static T GetT<T>(string key)
        {
            return (T)CustomCacheDictionary[key].Key;
        }
        public static bool IsExsits(string key)//判断缓存是否存在和是否过期
        {
            if (CustomCacheDictionary.ContainsKey(key))
            {
                if (CustomCacheDictionary[key].Value > DateTime.Now)
                {
                    return true;
                }
                else//过期,删除
                {
                    CustomCacheDictionary.Remove(key);
                    return false;
                }
            }
            else
            {
                return false;
            }
        }
        public static T GetDataT<T>(string key, Func<T> func)//Func是无参有返回值
        {
            T result = default(T);
            if (IsExsits(key))
            {
                result = (T)CustomCacheDictionary[key].Key;
            }
            else
            {
                result = func.Invoke();
                Add(key, result);
            }
            return result;
        }
    }
}

  Program:

using System;
using System.Threading.Tasks;
using System.Threading;
namespace ceshi
{
    class Program
    {
        static void Main(string[] args)
        {
            for (int i = 0; i < 500; i++)
            {
                string key = $"add_key_10_customcategory";//唯一准确描述缓存的key
                int result;
                result = CustomCache.GetDataT<int>(key, () => Simulation());
                Console.WriteLine(result);
                Thread.Sleep(1000);
            }
            Console.Read();
        }

        static int Simulation()
        {
            //-------------模拟获取数据的时耗--------------
            int result;
            Thread.Sleep(2000);
            Random random = new Random();
            result = random.Next(0, 100);
            return result;
        }
    }
}

  结果:

    

 

  我们定义缓存的过期时间是3秒后,当然现实中需要按要求合理定义过期时间,这里只是为了方便测试。

   以上这个方法还有一个缺陷,那就是如果一个缓存数据一直没有被访问到,那过期了也不会被判断并删除,会占用内存。

  所以,我们需要新开一个线程,让他实时进行过期检索操作。

  在类中添加一个构造函数,这样第一次使用这个类时,构造函数也会被调用,即可以马上打开这个线程进行监听

     static CustomCache()
        {
            Task.Run(() =>
            {
                while(true)
                {
                    List<string> keyList = new List<string>();
                    foreach(string item in CustomCacheDictionary.Keys)
                    {
                        if (CustomCacheDictionary[item].Value > DateTime.Now)
                        {
                            //还没过期,无需操作
                        }
                        else//过期,删除
                        {
                            keyList.Add(item);
                        }
                    }
                    keyList.ForEach(key => CustomCacheDictionary.Remove(key));
                    Thread.Sleep(60*1000);
                }
            });
        }

 4.缓存的使用场景

  适合使用缓存的资源一般具有以下特性

    //常用
    //耗时
    //稳定
    //即时性要求低
    //内存小

  举几个小例子

  可用于

    //session用户信息
    //权限数据
    //菜单
    //商品列表
    //基础资料 系统设置

  不可用于

    //股票数据
    //图片/视频

 

posted @ 2018-07-30 16:03  wskxy  阅读(1339)  评论(0编辑  收藏  举报