• Cache缓存(二) 安静点


    缓存过期策略

     如果数据库管理员来删除了数据呢,会存在缓存里面的数据不可用!缓存出现脏数据库;这是无法完全避免的;

    什么情况下使用缓存?

    二八原则     查询频繁;修改少!

     一般有如下三种策略:

     永不过期

    • 一直能够使用

     绝对过期

    • 过了多长时间以后,就过期了 就不能用了,此时可以直接将数据删除

     滑动过期

    • 设定好过期时间后,如果在有效期内使用过,就往后滑动  比如说,当前8点,设置到8点半过期,但是8点10分的时候使用过这个数据了,过期时间会滑动半小时,就是说8点40才会过期

     下面的缓存我们是通过字典自定义的, 如果存在多线程最好加锁:

    代码: 

      public class CustomCache
        {
            static CustomCache() //CLR调用  整个进程执行且只执行一次
            {
                Task.Run(() => //
                {
                    while (true) //死循环来判断
                    {
                        try
                        {
    
                            //Thread.Sleep(60 * 1000 * 10); //十分钟后开始清理缓存
                            List<string> delKeyList = new List<string>();
    
                            lock (obj_Lock)
                            {
                                foreach (var key in CustomCacheDictionary.Keys)
                                {
                                    DataModel model = CustomCacheDictionary[key];
                                    if (model.Deadline < DateTime.Now && model.ObsloteType != ObsloteType.Never) //
                                    {
                                        delKeyList.Add(key);
                                    }
                                }
                                delKeyList.ForEach(key => Remove(key));
                            } 
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine(ex.Message);
                            throw;
                        }
                    }
                });
    
            }
    
            /// <summary>
            /// static:不会被Gc回收;
            /// Private:不让外部访问他 
            /// </summary>
            private static Dictionary<string, DataModel> CustomCacheDictionary = new Dictionary<string, DataModel>();
    
            private static readonly object obj_Lock = new object();
    
    
            /// <summary>
            /// 默认你是不过期
            /// </summary>
            /// <param name="key"></param>
            /// <param name="value"></param>
            public static void Add(string key, object value)
            {
                lock (obj_Lock)
                    CustomCacheDictionary.Add(key, new DataModel()
                    {
                        Value = value,
                        ObsloteType = ObsloteType.Never
                    });
            }
    
            /// <summary>
            /// 绝对过期
            /// </summary>
            /// <param name="key"></param>
            /// <param name="value"></param>
            /// <param name="timeOutSecond"></param>
            public static void Add(string key, object value, int timeOutSecond) //3000
            {
                lock (obj_Lock)
                    CustomCacheDictionary.Add(key, new DataModel()
                    {
                        Value = value,
                        ObsloteType = ObsloteType.Absolutely,
                        Deadline = DateTime.Now.AddSeconds(timeOutSecond)
                    }); ;
            }
    
            public static void Add(string key, object value, TimeSpan durtion)
            {
                lock (obj_Lock)
                    CustomCacheDictionary.Add(key, new DataModel()
                    {
                        Value = value,
                        ObsloteType = ObsloteType.Relative,
                        Deadline = DateTime.Now.Add(durtion),
                        Duraton = durtion
                    }); ; ;
            }
    
    
            //清楚所有缓存,殃及池鱼!
            public static void RemoveAll()
            {
                lock (obj_Lock)
                    CustomCacheDictionary.Clear();//字典中的所有内容全部被清理到
            }
    
            public static void Remove(string key)
            {
                lock (obj_Lock)
                    CustomCacheDictionary.Remove(key);
            }
    
            /// <summary>
            /// 按条件删除
            /// </summary>
            /// <param name="func"></param>
            public static void RemoveCondition(Func<string, bool> func)
            {
                List<string> keyList = new List<string>();
                lock (obj_Lock)
                    foreach (var key in CustomCacheDictionary.Keys)
                    {
                        if (func.Invoke(key))
                        {
                            keyList.Add(key);
                        }
                    }
                keyList.ForEach(s => Remove(s));
            }
    
            public static T Get<T>(string key)
            {
                return (T)(CustomCacheDictionary[key]).Value;
            }
    
            /// <summary>
            /// 判断是否存在
            /// 判断是哪种过期策略,并且还要看是否过期,如果过期的话还要将数据删除
            /// 不过期的话  滑动过期的还将处理过期时间
            /// </summary>
            /// <param name="key"></param>
            /// <returns></returns>
            public static bool Exists(string key)
            {
                if (CustomCacheDictionary.ContainsKey(key))
                {
                    DataModel model = CustomCacheDictionary[key];
                    if (model.ObsloteType == ObsloteType.Never)
                    {
                        return true;
                    }
                    else if (model.Deadline < DateTime.Now) //
                    {
                        lock (obj_Lock)
                        {
    
                            CustomCacheDictionary.Remove(key);
                            return false;
                        }
    
                    }
                    else
                    {
                        if (model.ObsloteType == ObsloteType.Relative)
                        {
                            model.Deadline = DateTime.Now.Add(model.Duraton);
                        }
                        return true;
                    }
                }
                else
                {
                    return false;
                }
            }
    
            public static T GetT<T>(string key, Func<T> func)
            {
                T t = default(T);
                if (!Exists(key))
                {
                    t = func.Invoke();
                    Add(key, t);
                }
                else
                {
                    t = Get<T>(key);
                }
                return t;
            }
        }

     如果不想加锁,可以使用ConcurrentDictionary,会保证表示可由多个线程同时访问的键/值对的线程安全集合。

     代码示例:

      public class CustomCacheNew
        {
    
            static CustomCacheNew() //
            {
                Task.Run(() => //
                {
                    while (true) //死循环来判断
                    {
                        try
                        {
                            //Thread.Sleep(60 * 1000 * 10); //十分钟后开始清理缓存
                            List<string> delKeyList = new List<string>();
                            foreach (var key in CustomCacheDictionary.Keys)
                            {
                                DataModel model = CustomCacheDictionary[key];
                                if (model.Deadline < DateTime.Now && model.ObsloteType != ObsloteType.Never) //
                                {
                                    delKeyList.Add(key);
                                }
                            }
                            delKeyList.ForEach(key => Remove(key));
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine(ex.Message);
                            throw;
                        }
                    }
                });
    
            }
    
            /// <summary>
            /// static:不会被Gc回收;
            /// Private:不让外部访问他 
            /// 
            /// 线程安全字典
            /// </summary>
            private static ConcurrentDictionary<string, DataModel> CustomCacheDictionary = new ConcurrentDictionary<string, DataModel>();
    
            /// <summary>
            /// 默认你是不过期
            /// </summary>
            /// <param name="key"></param>
            /// <param name="value"></param>
            public static void Add(string key, object value)
            {
                CustomCacheDictionary.TryAdd(key, new DataModel()
                {
                    Value = value,
                    ObsloteType = ObsloteType.Never
                });
            }
    
            /// <summary>
            /// 绝对过期
            /// </summary>
            /// <param name="key"></param>
            /// <param name="value"></param>
            /// <param name="timeOutSecond"></param>
            public static void Add(string key, object value, int timeOutSecond) //3000
            {
                CustomCacheDictionary.TryAdd(key, new DataModel()
                {
                    Value = value,
                    ObsloteType = ObsloteType.Absolutely,
                    Deadline = DateTime.Now.AddSeconds(timeOutSecond)
                }); ;
            }
    
            public static void Add(string key, object value, TimeSpan durtion)
            {
                CustomCacheDictionary.TryAdd(key, new DataModel()
                {
                    Value = value,
                    ObsloteType = ObsloteType.Relative,
                    Deadline = DateTime.Now.Add(durtion),
                    Duraton = durtion
                }); ; ;
            }
    
    
            //清楚所有缓存,殃及池鱼!
            public static void RemoveAll()
            {
                CustomCacheDictionary.Clear();//字典中的所有内容全部被清理到
            }
    
            public static void Remove(string key)
            {
                DataModel data = null;
                CustomCacheDictionary.TryRemove(key, out data);
            }
    
            
            public static T Get<T>(string key)
            {
                return (T)(CustomCacheDictionary[key]).Value;
            }
    
            /// <summary>
            /// 判断是否存在
            /// </summary>
            /// <param name="key"></param>
            /// <returns></returns>
            public static bool Exists(string key)
            {
                
                if (CustomCacheDictionary.ContainsKey(key))
                {
                    DataModel model = CustomCacheDictionary[key];
                    if (model.ObsloteType == ObsloteType.Never)
                    {
                        return true;
                    }
                    else if (model.Deadline < DateTime.Now) //
                    {
                        DataModel data = null;
                        CustomCacheDictionary.TryRemove(key, out data);
                        return false;
                    }
                    else
                    {
                        if (model.ObsloteType == ObsloteType.Relative)
                        {
                            model.Deadline = DateTime.Now.Add(model.Duraton);
                        }
                        return true;
                    }
                }
                else
                {
                    return false;
                }
            }
    
            public static T GetT<T>(string key, Func<T> func)
            {
                T t = default(T);
                if (!Exists(key))
                {
                    t = func.Invoke();
                    Add(key, t);
                }
                else
                {
                    t = Get<T>(key);
                }
                return t;
            }
        }

     一般情况下我们都是使用字典加锁来实现,但是加锁的话就会造成性能上的问题,我们可以通过模拟CPU分片的方式来解决,这样锁的时候就锁了这一个字典缓存,另外几个字典不会被锁住

     代码:

        public class CustomCacheNewRichard
        {
    
            private static List<Dictionary<string, DataModel>> dicCacheList = new List<Dictionary<string, DataModel>>();
            private static List<object> lockList = new List<object>();
    
            public static int CupNum = 0;
            static CustomCacheNewRichard() //
            {
                CupNum = 3;//模拟获取获取CPU片数  
                //动态生成字典
                for (int i = 0; i < CupNum; i++)
                {
                    dicCacheList.Add(new Dictionary<string, DataModel>()); //CPU 有几片 就来几个字典
                    lockList.Add(new object());//每个字典对应一个锁
                }
    
    
                Task.Run(() => //
                {
                    while (true) //死循环来判断
                    {
                        try
                        {
    
                            for (int i = 0; i < CupNum; i++)
                            {
                                lock (lockList[i])
                                { 
                                    //Thread.Sleep(60 * 1000 * 10); //十分钟后开始清理缓存
                                    List<string> delKeyList = new List<string>();
                                    foreach (var key in dicCacheList[i].Keys)
                                    {
                                        DataModel model = dicCacheList[i][key];
                                        if (model.Deadline < DateTime.Now && model.ObsloteType != ObsloteType.Never) //
                                        {
                                            delKeyList.Add(key);
                                        }
                                    } 
                                    delKeyList.ForEach(key => dicCacheList[i].Remove(key));
                                }
                            }
    
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine(ex.Message);
                            throw;
                        }
                    }
                });
    
            }
    
            /// <summary>
            /// 默认你是不过期
            /// </summary>
            /// <param name="key"></param>
            /// <param name="value"></param>
            public static void Add(string key, object value)
            {
                int hash = key.GetHashCode() * (-1); //只要字符串不变,hash值不变!
                int index = hash % CupNum;
                lock (lockList[index])
                    dicCacheList[index].Add(key, new DataModel()
                    {
                        Value = value,
                        ObsloteType = ObsloteType.Never
                    });
            }
    
            /// <summary>
            /// 绝对过期
            /// </summary>
            /// <param name="key"></param>
            /// <param name="value"></param>
            /// <param name="timeOutSecond"></param>
            public static void Add(string key, object value, int timeOutSecond) //3000
            {
                int hash = key.GetHashCode() * (-1); //只要字符串变,hash值不变!
                int index = hash % CupNum;
                lock (lockList[index])
                    dicCacheList[index].Add(key, new DataModel()
                    {
                        Value = value,
                        ObsloteType = ObsloteType.Absolutely,
                        Deadline = DateTime.Now.AddSeconds(timeOutSecond)
                    }); ;
            }
    
            public static void Add(string key, object value, TimeSpan durtion)
            {
                int hash = key.GetHashCode() * (-1); //只要字符串变,hash值不变!
                int index = hash % CupNum;
                lock (lockList[index])
                    dicCacheList[index].Add(key, new DataModel()
                    {
                        Value = value,
                        ObsloteType = ObsloteType.Relative,
                        Deadline = DateTime.Now.Add(durtion),
                        Duraton = durtion
                    }); ; ;
            }
    
    
            //清楚所有缓存,殃及池鱼!
            public static void RemoveAll()
            {
                for (int i = 0; i < CupNum; i++)
                {
                    dicCacheList[i].Clear();
                }
            }
    
            public static void Remove(string key)
            {
                int hash = key.GetHashCode() * (-1); //只要字符串变,hash值不变!
                int index = hash % CupNum;
    
                if (dicCacheList[index].ContainsKey(key))
                {
                    dicCacheList[index].Remove(key);
                }
    
            }
    
           
            public static T Get<T>(string key)
            {
                int hash = key.GetHashCode() * (-1); //只要字符串变,hash值不变!
                int index = hash % CupNum;
    
                return (T)(dicCacheList[index][key]).Value;
            }
    
            /// <summary>
            /// 判断是否存在
            /// </summary>
            /// <param name="key"></param>
            /// <returns></returns>
            public static bool Exists(string key)
            {
                int hash = key.GetHashCode() * (-1); //只要字符串变,hash值不变!
                int index = hash % CupNum;
                if (dicCacheList[index].ContainsKey(key))
                {
                    DataModel model = dicCacheList[index][key];
                    if (model.ObsloteType == ObsloteType.Never)
                    {
                        return true;
                    }
                    else if (model.Deadline < DateTime.Now) //
                    {
                        dicCacheList[index].Remove(key);
                        return false;
                    }
                    else
                    {
                        if (model.ObsloteType == ObsloteType.Relative)
                        {
                            model.Deadline = DateTime.Now.Add(model.Duraton);
                        }
                        return true;
                    }
                }
                else
                {
                    return false;
                }
            }
    
            public static T GetT<T>(string key, Func<T> func)
            {
                T t = default(T);
                if (!Exists(key))
                {
                    t = func.Invoke();
                    Add(key, t);
                }
                else
                {
                    t = Get<T>(key);
                }
                return t;
            }
        }

     上面的代码是自己定义的,我们可以使用系统框架自定义的MemoryCacheCache

     MemoryCacheCache

     它的本质其实也是类似于CPU分片实现的,封装的代码如下:

    namespace Common
    {
        /// <summary>
        /// Cache manager interface
        /// </summary>
        public interface ICache
        {
            /// <summary>
            /// Gets or sets the value associated with the specified key.
            /// </summary>
            /// <typeparam name="T">Type</typeparam>
            /// <param name="key">The key of the value to get.</param>
            /// <returns>The value associated with the specified key.</returns>
            T Get<T>(string key);
    
            /// <summary>
            /// Adds the specified key and object to the cache.
            /// </summary>
            /// <param name="key">key</param>
            /// <param name="data">Data</param>
            /// <param name="cacheTime">Cache time</param>
            void Add(string key, object data, int cacheTime = 30);
    
            /// <summary>
            /// Gets a value indicating whether the value associated with the specified key is cached
            /// </summary>
            /// <param name="key">key</param>
            /// <returns>Result</returns>
            bool Contains(string key);
    
            /// <summary>
            /// Removes the value with the specified key from the cache
            /// </summary>
            /// <param name="key">/key</param>
            void Remove(string key);
    
            /// <summary>
            /// Clear all cache data
            /// </summary>
            void RemoveAll();
    
            object this[string key] { get; set; }
    
            int Count { get; }
        }
    }

    MemoryCacheCache

    /// <summary>
        /// MemoryCacheCache
        /// </summary>
        public class MemoryCacheCache : ICache
        {
            public MemoryCacheCache() { }
    
            protected ObjectCache Cache
            {
                get
                {
                    return MemoryCache.Default;
                }
            }
    
            /// <summary>
            /// 读取缓存
            /// </summary>
            /// <typeparam name="T"></typeparam>
            /// <param name="key"></param>
            /// <returns></returns>
            public T Get<T>(string key)
            {
                if (Cache.Contains(key))
                {
                    return (T)Cache[key];
                }
                else
                {
                    return default(T);
                }
            }
    
            public object Get(string key)
            {
                return Cache[key];
            }
    
            /// <summary>
            /// 增加缓存
            /// </summary>
            /// <param name="key"></param>
            /// <param name="data"></param>
            /// <param name="cacheTime">分钟</param>
            public void Add(string key, object data, int cacheTime = 30)
            {
                if (data == null)
                    return;
    
                var policy = new CacheItemPolicy();
                policy.AbsoluteExpiration = DateTime.Now + TimeSpan.FromMinutes(cacheTime);
                Cache.Add(new CacheItem(key, data), policy);
            }
    
            /// <summary>
            /// 是否包含
            /// </summary>
            /// <param name="key"></param>
            /// <returns></returns>
            public bool Contains(string key)
            {
                return Cache.Contains(key);
            }
    
            public int Count { get { return (int)(Cache.GetCount()); } }
    
    
            /// <summary>
            /// 单个清除
            /// </summary>
            /// <param name="key">/key</param>
            public void Remove(string key)
            {
                Cache.Remove(key);
            }
    
            /// <summary>
            /// 正则表达式移除
            /// </summary>
            /// <param name="pattern">pattern</param>
            public void RemoveByPattern(string pattern)
            {
                var regex = new Regex(pattern, RegexOptions.Singleline | RegexOptions.Compiled | RegexOptions.IgnoreCase);
                var keysToRemove = new List<String>();
    
                foreach (var item in Cache)
                    if (regex.IsMatch(item.Key))
                        keysToRemove.Add(item.Key);
    
                foreach (string key in keysToRemove)
                {
                    Remove(key);
                }
            }
    
            /// <summary>
            /// 根据键值返回缓存数据
            /// </summary>
            /// <param name="key"></param>
            /// <returns></returns>
            public object this[string key]
            {
                get { return Cache.Get(key); }
                set { Add(key, value); }
            }
    
            /// <summary>
            /// 清除全部数据
            /// </summary>
            public void RemoveAll()
            {
                foreach (var item in Cache)
                    Remove(item.Key);
            }
        }

    CacheManager

       public class CacheManager
        {
            #region Identity
            private CacheManager()
            { }
    
            private static ICache cache = null;
    
            static CacheManager()
            {
                Console.WriteLine("开始缓存的初始化.....");
                //可以创建不同的cache对象
                cache = (ICache)Activator.CreateInstance(typeof(MemoryCacheCache));
                // 这里可以根据配置文件来选择
                //cache = (ICache)Activator.CreateInstance(typeof(CustomerCache));
            }
            #endregion Identity
    
            #region ICache
            /// <summary>
            /// 当前缓存数据项的个数
            /// </summary>
            public static int Count
            {
                get { return cache.Count; }
            }
    
            /// <summary>
            /// 如果缓存中已存在数据项键值,则返回true
            /// </summary>
            /// <param name="key">数据项键值</param>
            /// <returns>数据项是否存在</returns>
            public static bool Contains(string key)
            {
                return cache.Contains(key);
            }
    
            /// <summary>
            /// 获取缓存数据
            /// </summary>
            /// <param name="key"></param>
            /// <returns></returns>
            public static T GetData<T>(string key)
            {
                return cache.Get<T>(key);
            }
    
            /// <summary>
            /// 
            /// </summary>
            /// <typeparam name="T"></typeparam>
            /// <param name="key">缓存的项</param>
            /// <param name="acquire">没有缓存的时候获取数据的方式</param>
            /// <param name="cacheTime">单位分钟  默认30</param>
            /// <returns></returns>
            public static T Get<T>(string key, Func<T> acquire, int cacheTime = 30)
            {
                if (!cache.Contains(key))
                {
                    T result = acquire.Invoke();
                    cache.Add(key, result, cacheTime);
                }
                return GetData<T>(key);
    
                //if (cache.Contains(key))
                //{
                //    return GetData<T>(key);
                //}
                //else
                //{
                //    T result = acquire.Invoke();//执行委托  获取委托结果   作为缓存值
                //    cache.Add(key, result, cacheTime);
                //    return result;
                //}
            }
    
            /// <summary>
            /// 添加缓存数据。
            /// 如果另一个相同键值的数据已经存在,原数据项将被删除,新数据项被添加。
            /// </summary>
            /// <param name="key">缓存数据的键值</param>
            /// <param name="value">缓存的数据,可以为null值</param>
            /// <param name="expiratTime">缓存过期时间间隔(单位:分钟)</param>
            public static void Add(string key, object value, int expiratTime = 30)
            {
                if (Contains(key))
                    cache.Remove(key);
                cache.Add(key, value, expiratTime);
            }
    
            /// <summary>
            /// 删除缓存数据项
            /// </summary>
            /// <param name="key"></param>
            public static void Remove(string key)
            {
                cache.Remove(key);
            }
    
            /// <summary>
            /// 删除所有缓存数据项
            /// </summary>
            public static void RemoveAll()
            {
                cache.RemoveAll();
            }
            #endregion
    
        }

      

  • 相关阅读:
    vue路由的简单实例
    webpack配置sass模块的加载
    jQuery停止动画——stop()方法的使用
    jQuery检查某个元素在页面上是否存在
    js获取鼠标当前的位置
    js实现一些跨浏览器的事件方法
    逐个访问URL的每个查询字符串参数
    《锋利的jQuery》(第2版)读书笔记4
    jQuery与Ajax的应用——《锋利的jQuery》(第2版)读书笔记3
    jQuery中的事件和动画——《锋利的jQuery》(第2版)读书笔记2
  • 原文地址:https://www.cnblogs.com/anjingdian/p/16884100.html
Copyright © 2020-2023  润新知