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

    }

 

  

posted @ 2022-11-12 16:39  安静点--  阅读(66)  评论(0)    收藏  举报