.Net Core3.0 WebApi 項目框架搭建 十七:使用NewLife.Redis替換掉原來的Redis


 

 .Net Core3.0 WebApi 項目框架搭建:目錄

 

介紹

  • NewLife.Redis主要作者及經驗介紹來源:大石頭
  • 源碼: https://github.com/NewLifeX/NewLife.Redis
  • Nuget:NewLife.Redis
  • NewLife.Redis是一個Redis客戶端組件,以高性能處理大數據實時計算為目標。
  • Redis協議基礎實現Redis/RedisClient位於X組件,包含基礎字符串操作。完整實現由獨立開源項目NewLife.Redis提供。NewLife.Redis為擴展實現,主要增加列表結構、哈希結構、隊列等高級功能。
  • 采取連接池加同步阻塞架構,具有超低延遲(200~600us)以及超高吞吐量的特點。在物流行業大數據實時計算中廣泛應有,經過日均100億次調用量驗證。

特性

  • 在ZTO大數據實時計算廣泛應用,200多個Redis實例穩定工作一年多,每天處理近1億包裹數據,日均調用量80億次

  • 低延遲,Get/Set操作平均耗時200~600us(含往返網絡通信)

  • 大吞吐,自帶連接池,最大支持1000並發

更新Redis接口

    public interface IRedisCacheManager
    {

        #region
        #endregion


        #region 普通

        /// <summary>
        /// 獲取值,並序列化
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="key"></param>
        /// <returns></returns>
        TEntity Get<TEntity>(string key);

        /// <summary>
        /// 插入數據到redis
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <param name="cacheTime"></param>
        void Set(string key, object value, TimeSpan cacheTime);

        /// <summary>
        /// 插入數據到redis
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <param name="cacheTime"></param>
        void Set<TEntity>(string key, TEntity value, TimeSpan cacheTime);

        /// <summary>
        /// 判斷是否存在
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        bool ContainsKey(string key);

        /// <summary>
        /// 移除某一個key
        /// </summary>
        /// <param name="key"></param>
        void Remove(string key);

        /// <summary>
        /// 全部清除
        /// </summary>
        void Clear();

        /// <summary>
        /// 設置超時
        /// </summary>
        /// <param name="key"></param>
        /// <param name="timeSpan"></param>
        void SetExpire(string key, TimeSpan timeSpan);

        /// <summary>
        /// 根據關鍵字移除
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        Task RemoveByKey(string key, int count);
        /// <summary>
        /// 根據關鍵字移除所有
        /// </summary>
        /// <param name="key"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        Task RemoveAllByKey(string key, int count = 999);

        #endregion

        #region HashMap
        /// <summary>
        /// 插入hashmap
        /// </summary>
        /// <param name="name"></param>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <param name="expire"></param>
        /// <returns></returns>
        bool HashSet<T>(string key, Dictionary<string, T> dic, int expire = -1);

        /// <summary>
        /// /插入hashmap帶返回結果
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="dic"></param>
        /// <param name="expire"></param>
        /// <returns></returns>
        bool HashSetWithResult<T>(string key, Dictionary<string, T> dic, int expire = -1);

        /// <summary>
        /// 獲取hashmap
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="fields"></param>
        /// <returns></returns>
        List<T> HashGet<T>(string key, params string[] fields);

        /// <summary>
        /// 獲取hashmap
        /// </summary>
        /// <param name="name"></param>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <param name="expire"></param>
        /// <returns></returns>
        string[] HashGet(string key, params string[] fields);

        #endregion

        #region 隊列
        /// <summary>
        /// 添加到隊列
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        int AddQueue<T>(string key, T[] value);

        /// <summary>
        /// 獲取一批隊列消息
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        List<T> GetQueue<T>(string key, int Count);

        /// <summary>
        /// 獲取一個隊列消息
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        Task<T> GetQueueOneAsync<T>(string key);
        #endregion

        #region 可靠隊列
        /// <summary>
        /// 獲取可靠隊列實例
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <returns></returns>
        RedisReliableQueue<T> GetReliableQueue<T>(string key);

        /*
        /// <summary>
        /// 批量獲取可靠隊列消息
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="queue"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        Task<List<T>> GetReliableQueueMsgAsync<T>(RedisReliableQueue<T> queue, int count);

        /// <summary>
        /// 獲取一條可靠隊列消息
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="queue"></param>
        /// <returns></returns>
        Task<T> GetReliableQueueMsgAsync<T>(RedisReliableQueue<T> queue);

        /// <summary>
        /// 回滾所有未確認消息
        /// </summary>
        /// <param name="key"></param>
        /// <param name="retryInterval">重新處理確認隊列中死信的間隔。默認60s</param>
        /// <returns></returns>
        Task<int> RollbackAllAck(string key, int retryInterval = 60);

        /// <summary>
        /// 確認消息
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        Task<int> Acknowledge<T>(RedisReliableQueue<T> queue, T value);
        */

        /// <summary>
        /// 批量添加消息到可靠隊列
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        int AddReliableQueueList<T>(string key, List<T> value);
        /// <summary>
        /// 添加消息到可靠隊列
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        int AddReliableQueue<T>(string key, T value);
        /// <summary>
        /// 回滾所有未確認消息
        /// </summary>
        /// <param name="key"></param>
        /// <param name="retryInterval">重新處理確認隊列中死信的間隔。默認60s</param>
        /// <returns></returns>
        int RollbackAllAck(string key, int retryInterval = 60);
        #endregion

        #region 列表
        /// <summary>
        /// 插入列表
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="values"></param>
        /// <param name="timeSpan"></param>
        /// <returns></returns>
        int AddList(string key, IEnumerable<string> values, TimeSpan timeSpan);

        /// <summary>
        /// 列表
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="values"></param>
        /// <returns></returns>
        int AddList(string key, IEnumerable<string> values);


        #endregion
        #region SortSet
        /// <summary>
        /// 獲取SortSet實例
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <returns></returns>
        RedisSortedSet<T> GetRedisSortedSet<T>(string key);
        /// <summary>
        /// 批量添加Sorted
        /// 將所有指定成員添加到鍵為key有序集合(sorted set)里面。 添加時可以指定多個分數/成員(score/member)對。
        /// 如果指定添加的成員已經是有序集合里面的成員,則會更新改成員的分數(scrore)並更新到正確的排序位置。
        /// ZADD 命令在key后面分數/成員(score/member)對前面支持一些參數,他們是:
        /// XX: 僅僅更新存在的成員,不添加新成員。
        /// NX: 不更新存在的成員。只添加新成員。
        /// CH: 修改返回值為發生變化的成員總數,原始是返回新添加成員的總數(CH 是 changed 的意思)。
        /// 更改的元素是新添加的成員,已經存在的成員更新分數。 所以在命令中指定的成員有相同的分數將不被計算在內。
        /// 注:在通常情況下,ZADD返回值只計算新添加成員的數量。
        /// INCR: 當ZADD指定這個選項時,成員的操作就等同ZINCRBY命令,對成員的分數進行遞增操作。
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <param name="options"></param>
        /// <returns></returns>
        int SortedSetAdd(string key, Dictionary<String, Double> value, string options = null);

        /// <summary>為有序集key的成員member的score值加上增量increment</summary>
        /// <param name="member"></param>
        /// <param name="score"></param>
        /// <returns></returns>
        double SortedSetIncrement<T>(string key, T member, double score);

        /// <summary>刪除並返回有序集合key中的最多count個具有最高得分的成員</summary>
        /// <param name="count"></param>
        /// <returns></returns>
        IDictionary<T, double> SortedSetPopMax<T>(string key, int count = 1);


        /// <summary>刪除並返回有序集合key中的最多count個具有最低得分的成員</summary>
        /// <param name="count"></param>
        /// <returns></returns>
        IDictionary<T, double> SortedSetPopMin<T>(string key, int count = 1);
        /// <summary>
        /// 返回有序集key中,score值在min和max之間(默認包括score值等於min或max)的成員個數
        /// </summary>
        /// <param name="min"></param>
        /// <param name="max"></param>
        /// <returns></returns>
        int SortedSetFindCount<T>(string key, double min, double max);

        /// <summary>返回指定范圍的列表</summary>
        /// <param name="start"></param>
        /// <param name="stop"></param>
        /// <returns></returns>
        T[] SortedSetRange<T>(string key, int start, int stop);

        /// <summary>返回指定范圍的成員分數對</summary>
        /// <param name="start"></param>
        /// <param name="stop"></param>
        /// <returns></returns>
        IDictionary<T, double> SortedSetRangeWithScores<T>(string key, int start, int stop);

        /// <summary>返回指定分數區間的成員列表,低分到高分排序</summary>
        /// <param name="min">低分,包含</param>
        /// <param name="max">高分,包含</param>
        /// <param name="offset">偏移</param>
        /// <param name="count">個數</param>
        /// <returns></returns>
        T[] SortedSetRangeByScore<T>(string key, double min, double max, int offset, int count);

        /// <summary>返回指定分數區間的成員列表,低分到高分排序</summary>
        /// <param name="min">低分,包含</param>
        /// <param name="max">高分,包含</param>
        /// <param name="offset">偏移</param>
        /// <param name="count">個數</param>
        /// <returns></returns>
        Task<T[]> SortedSetRangeByScoreAsync<T>(string key, double min, double max, int offset, int count);
        /// <summary>返回指定分數區間的成員分數對,低分到高分排序</summary>
        /// <param name="min">低分,包含</param>
        /// <param name="max">高分,包含</param>
        /// <param name="offset">偏移</param>
        /// <param name="count">個數</param>
        /// <returns></returns>
        IDictionary<T, double> SortedSetRangeByScoreWithScores<T>(string key, double min, double max, int offset, int count);
        /// <summary>返回有序集key中成員member的排名。其中有序集成員按score值遞增(從小到大)順序排列</summary>
        /// <param name="member"></param>
        /// <returns></returns>
        int SortedSetRank<T>(string key, T member);
        /// <summary>模糊搜索,支持?和*</summary>
        /// <param name="pattern"></param>
        /// <param name="count"></param>
        /// <param name="position"></param>
        /// <returns></returns>
        IEnumerable<KeyValuePair<T, double>> SortedSetSearch<T>(string key, string pattern, int count, int position = 0);
        #endregion
        #region Set
        /// <summary>
        /// 添加Set
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        void SetAdd<T>(string key, T value);
        /// <summary>
        /// 批量添加添加Set
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        void SetAddList<T>(string key, T[] value);
        /// <summary>
        /// 移除Set某個值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        bool SetRemove<T>(string key, T value);
        /// <summary>
        /// 判斷值是否存在
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        bool SetContains<T>(string key, T value);
        /// <summary>
        /// 清空Set
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <returns></returns>
        void SetClear<T>(string key);
        /// <summary>
        /// 復制Set
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="array"></param>
        /// <param name="arrayIndex"></param>
        /// <returns></returns>
        void SetCopyTo<T>(string key, T[] array, int arrayIndex);



        #endregion

    }
IRedisCacheManager

添加實現類

Common類庫中,新建Redis文件夾,新建NewLifeRedisCacheManager.cs

  public class NewLifeRedisCacheManager : IRedisCacheManager
    {
        private readonly string redisConnenctionString;
        public volatile FullRedis redisConnection;
        private readonly object redisConnectionLock = new object();
        private readonly int db;
        public NewLifeRedisCacheManager()
        {
            string redisConfiguration = Appsettings.App(new string[] { "AppSettings", "RedisCaching", "ConnectionString" });//獲取連接字符串
            string Db = Appsettings.App(new string[] { "AppSettings", "RedisCaching", "Db" });
            if (string.IsNullOrWhiteSpace(redisConfiguration))
            {
                throw new ArgumentException("redis config is empty", nameof(redisConfiguration));
            }
            FullRedis.Register();
            this.redisConnenctionString = redisConfiguration;
            this.db = Db.ToInt();
            this.redisConnection = GetRedisConnection();
        }
        public NewLifeRedisCacheManager(string redisConfiguration, int Db = 0)
        {
            if (string.IsNullOrWhiteSpace(redisConfiguration))
            {
                throw new ArgumentException("redis config is empty", nameof(redisConfiguration));
            }
            FullRedis.Register();
            this.redisConnenctionString = redisConfiguration;
            this.db = Db.ToInt();
            this.redisConnection = GetRedisConnection();
        }
        /// <summary>
        /// 核心代碼,獲取連接實例
        /// 通過雙if 夾lock的方式,實現單例模式
        /// </summary>
        /// <returns></returns>
        private FullRedis GetRedisConnection()
        {
            //如果已經連接實例,直接返回
            if (this.redisConnection != null)
            {
                return this.redisConnection;
            }
            //加鎖,防止異步編程中,出現單例無效的問題
            lock (redisConnectionLock)
            {
                if (this.redisConnection != null)
                {
                    //釋放redis連接
                    this.redisConnection.Dispose();
                }
                try
                {
                    //this.redisConnection = FullRedis.Create(redisConnenctionString);
                    this.redisConnection = FullRedis.Create(redisConnenctionString);
                    this.redisConnection.Timeout = 5000;
                }
                catch (Exception ex)
                {

                    throw new Exception("Redis服務未啟用,請開啟該服務");
                }
            }
            return this.redisConnection;
        }


        #region 普通
        public TEntity Get<TEntity>(string key)
        {
            return redisConnection.Get<TEntity>(key);
        }

        public void Set<TEntity>(string key, TEntity value, TimeSpan cacheTime)
        {
            if (value != null)
            {
                redisConnection.Set(key, value, cacheTime);
            }
        }

        public void Set(string key, object value, TimeSpan cacheTime)
        {
            redisConnection.Set(key, value, cacheTime);
        }

        public bool ContainsKey(string key)
        {
            return redisConnection.ContainsKey(key);
        }

        public void Remove(string key)
        {
            redisConnection.Remove(key);
        }

        public void Clear()
        {
            redisConnection.Clear();
        }

        public void SetExpire(string key, TimeSpan timeSpan)
        {
            redisConnection.SetExpire(key, timeSpan);
        }


        public async Task RemoveByKey(string key, int count)
        {
            await Task.Run(() =>
            {
                var keys = redisConnection.Search(key, count).ToList();
                foreach (var k in keys)
                    redisConnection.Remove(k);
            });
        }

        public async Task RemoveAllByKey(string key, int count = 999)
        {
            await Task.Run(() =>
            {
                while (true)
                {
                    var keyList = redisConnection.Search(key, count).ToList();
                    if (keyList.Count > 0)
                    {
                        foreach (var k in keyList)
                            redisConnection.Remove(k);
                    }
                    else
                    {
                        break;
                    }
                }
            });
        }

        #endregion

        #region HashMap
        public bool HashSetWithResult<T>(string key, Dictionary<string, T> dic, int expire = -1)
        {
            var hash = redisConnection.GetDictionary<T>(key) as RedisHash<string, T>;
            var result = hash.HMSet(dic);
            return result;

        }

        public bool HashSet<T>(string key, Dictionary<string, T> dic, int expire = -1)
        {
            var hash = redisConnection.GetDictionary<T>(key) as RedisHash<string, T>;
            var result = hash.HMSet(dic);
            return result;
        }

        public string[] HashGet(string key, params string[] fields)
        {
            var hash = redisConnection.GetDictionary<string>(key) as RedisHash<string, string>;
            var result = hash.HMGet(fields);
            return result;
        }

        public List<T> HashGet<T>(string key, params string[] fields)
        {
            var hash = redisConnection.GetDictionary<T>(key) as RedisHash<string, T>;
            var result = hash.HMGet(fields);
            return result.ToList();
        }
        #endregion

        #region 隊列

        public int AddQueue<T>(string key, T[] value)
        {
            var queue = redisConnection.GetQueue<T>(key);
            return queue.Add(value);
        }



        public List<T> GetQueue<T>(string key, int Count = 1)
        {
            var queue = redisConnection.GetQueue<T>(key);
            var result = queue.Take(Count).ToList();
            return result;
        }

        public async Task<T> GetQueueOneAsync<T>(string key)
        {
            var queue = redisConnection.GetQueue<T>(key);
            return await queue.TakeOneAsync(1);
        }
        #endregion

        #region 可靠隊列
        public RedisReliableQueue<T> GetReliableQueue<T>(string key)
        {
            var queue = redisConnection.GetReliableQueue<T>(key);
            return queue;
        }
        /* 
        public async Task<List<T>> GetReliableQueueMsgAsync<T>(RedisReliableQueue<T> queue, int count)
        {
            return await Task.Run(() =>
            {
                return queue.Take(count).ToList();
            });
        }

        public async Task<T> GetReliableQueueMsgAsync<T>(RedisReliableQueue<T> queue)
        {
            return await Task.Run(() =>
            {
                return queue.TakeOne();
            });
        }
        public async Task<int> Acknowledge<T>(RedisReliableQueue<T> queue, T value)
        {
            return await Task.Run(() =>
             {
                 var data = value.ToJson();
                 var count = queue.Acknowledge(data);
                 return count;
             });
        }


        */
        public int RollbackAllAck(string key, int retryInterval = 60)
        {
            var queue = redisConnection.GetReliableQueue<string>(key);
            queue.RetryInterval = retryInterval;
            return queue.RollbackAllAck();
        }

        public int AddReliableQueueList<T>(string key, List<T> value)
        {
            var queue = redisConnection.GetReliableQueue<T>(key);
            return queue.Add(value.ToArray());
        }

        public int AddReliableQueue<T>(string key, T value)
        {
            var queue = redisConnection.GetReliableQueue<T>(key);
            return queue.Add(value);
        }
        #endregion

        #region 列表
        public int AddList(string key, IEnumerable<string> values, TimeSpan timeSpan)
        {
            var list = redisConnection.GetList<string>(key) as RedisList<string>;
            redisConnection.SetExpire(key, timeSpan);
            return list.AddRange(values);
        }
        public int AddList(string key, IEnumerable<string> values)
        {
            var list = redisConnection.GetList<string>(key) as RedisList<string>;
            return list.AddRange(values);
        }

        public async Task<string> GetListAsync(string key, string value)
        {
            return await Task.Run(() =>
               {
                   var list = redisConnection.GetList<string>(key) as RedisList<string>;
                   return list[list.IndexOf(value)];
               });
        }


        #endregion

        #region SortSet

        public RedisSortedSet<T> GetRedisSortedSet<T>(string key)
        {
            var zset = new RedisSortedSet<T>(redisConnection, key);
            return zset;
        }
        public int SortedSetAdd(string key, Dictionary<string, double> value, string options = null)
        {
            var zset = new RedisSortedSet<string>(redisConnection, key);
            return zset.Add(options, value);
        }

        public IDictionary<T, double> SortedSetPopMax<T>(string key, int count = 1)
        {
            var zset = new RedisSortedSet<T>(redisConnection, key);
            return zset.PopMax(count);
        }
        public IDictionary<T, double> SortedSetPopMin<T>(string key, int count = 1)
        {
            var zset = new RedisSortedSet<T>(redisConnection, key);
            return zset.PopMin(count);
        }

        public int SortedSetFindCount<T>(string key, double min, double max)
        {
            var zset = new RedisSortedSet<T>(redisConnection, key);
            return zset.FindCount(min, max);
        }

        public T[] SortedSetRange<T>(string key, int start, int stop)
        {
            var zset = new RedisSortedSet<T>(redisConnection, key);
            return zset.Range(start, stop);
        }

        public IDictionary<T, double> SortedSetRangeWithScores<T>(string key, int start, int stop)
        {
            var zset = new RedisSortedSet<T>(redisConnection, key);
            return zset.RangeWithScores(start, stop);
        }
        public T[] SortedSetRangeByScore<T>(string key, double min, double max, int offset, int count)
        {
            var zset = new RedisSortedSet<T>(redisConnection, key);
            return zset.RangeByScore(min, max, offset, count);
        }

        public async Task<T[]> SortedSetRangeByScoreAsync<T>(string key, double min, double max, int offset, int count)
        {
            var zset = new RedisSortedSet<T>(redisConnection, key);
            return await zset.RangeByScoreAsync(min, max, offset, count);
        }
        public IDictionary<T, double> SortedSetRangeByScoreWithScores<T>(string key, double min, double max, int offset, int count)
        {
            var zset = new RedisSortedSet<T>(redisConnection, key);
            return zset.RangeByScoreWithScores(min, max, offset, count);
        }

        public int SortedSetRank<T>(string key, T member)
        {
            var zset = new RedisSortedSet<T>(redisConnection, key);
            return zset.Rank(member);
        }
        public IEnumerable<KeyValuePair<T, double>> SortedSetSearch<T>(string key, string pattern, int count, int position = 0)
        {
            var zset = new RedisSortedSet<T>(redisConnection, key);
            return zset.Search(pattern, count, position);

        }

        public double SortedSetIncrement<T>(string key, T member, double score)
        {
            var zset = new RedisSortedSet<T>(redisConnection, key);
            return zset.Increment(member, score);
        }
        #endregion

        #region Set
        public void SetAdd<T>(string key, T value)
        {
            var set = redisConnection.GetSet<T>(key);
            set.Add(value);
        }
        public void SetAddList<T>(string key, T[] value)
        {
            var set = redisConnection.GetSet<string>(key);
            var set2 = set as RedisSet<T>;
            set2.SAdd(value);
        }

        public bool SetRemove<T>(string key, T value)
        {
            var set = redisConnection.GetSet<T>(key);
            return set.Remove(value);
        }
        public bool SetContains<T>(string key, T value)
        {
            var set = redisConnection.GetSet<T>(key);
            return set.Contains(value);
        }

        public void SetClear<T>(string key)
        {
            var set = redisConnection.GetSet<T>(key);
            set.Clear();
        }

        public void SetCopyTo<T>(string key, T[] array, int arrayIndex)
        {
            var set = redisConnection.GetSet<T>(key);
            set.CopyTo(array, arrayIndex);
        }
        #endregion




    }
NewLifeRedisCacheManager

啟動文件注入

 services.AddSingleton<IRedisCacheManager, NewLifeRedisCacheManager>();

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM