zoukankan      html  css  js  c++  java
  • Redis缓存项目应用架构设计一

    一些项目整理出的项目中引入缓存的架构设计方案,希望能帮助你更好地管理项目缓存,作者水平有限,如有不足还望指点。

    一、基础结构介绍

    项目中对外提供方法的是CacheProvider和MQProvider两个类,一切缓存或队列应用都从这里做入口,后期更换缓存或队列只需要更改后面的提供者即可

    主要结构设计分为三部分:

    1、Key管理(用于管理缓存Key、过期时间、是否启用、调用识别Key等)

    Configs -> Cache -> KeyConfigList.xml(配置Key的具体信息)

    Cache -> Key -> KeyEntity.cs(XML的序列化对象)

    Cache -> Key -> KeyManager.cs(读取XML并监听XML文件的变更,如果变更重新读取)

    Cache -> Key -> KeyNames.cs(Key名称的枚举,控制Key从这里集中管理,不会到处都是)

    2、内部操作(对接的多个缓存实际提供技术比如Redis、Memcached、LocalCache等)

    Cache -> Redis -> RedisManager.cs(Redis的连接对象及基本配置)

    3、对外提供(对项目中应用缓存提供支持函数,如更改缓存提供技术只需从这里调整代码,不影响项目主体代码)

    Cache -> CacheProvider.cs(项目中的缓存操作提供函数类)

    MQ -> MQProvider.cs(项目中的队列操作提供函数类)

     

    二、代码详细介绍

    1、KeyConfigList.xml

    用于存储缓存中数据的Key、有效时间、是否启用此缓存等配置信息

    name:用来寻找此条Key信息的标识

    key:缓存中存的Key

    validTime:便于计算此缓存的有效时间,比如只缓存5分钟

    enabled:是否启用此缓存,不启用则每次都读库

    {0}、{1}、{2}:缓存Key的占位符用于区分某个类型的缓存其中的一个,比如商品缓存格式为Goods:{0},可能实际存储Key是Goods:1、Goods:2、Goods:3,这个1、2、3是商品Id来区分具体某个,如果量大禁用时会导致缓存雪崩,可以考虑再根据类型或其他来细分

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <!-- name:程序key、key:缓存key(用:冒号来对缓存数据进行分级)、 validTime:有效时间(单位:分)、enabled:是否有效、{0}:占位符替换相关id等标识 -->
      <list>
        <!-- 一个占位符key -->
        <item name="Admin_User_Session" key="Admin:User:Session:{0}" validTime="60" enabled="true"></item>
        <!-- 无占位符key -->
        <item name="Admin_User_List" key="Admin:User:List" validTime="30" enabled="true"></item>
        <!-- 多个占位符key -->
        <item name="Admin_User_Search" key="Admin:User:Search:{0}:{1}:{2}" validTime="5" enabled="true"></item>
      </list>
    </configuration>

     2、KeyEntity.cs

    这个比较简单,就是把xml的内容读取出来序列化为对象,只是为了便于检索,name和key都小写化了

        /// <summary>
        /// Key配置对象(公开)
        /// Author:taiyonghai
        /// CreateTime:2017-08-28
        /// </summary>
        public sealed class KeyEntity
        {
            private string name;
            /// <summary>
            /// Cache Name(Use for search cache key)
            /// </summary>
            public string Name
            {
                get { return name; }
                set { name = value.Trim().ToLower(); }
            }
    
            private string key;
            /// <summary>
            /// Cache Key
            /// </summary>
            public string Key
            {
                get { return key; }
                set { key = value.Trim().ToLower(); }
            }
    
            /// <summary>
            /// Valid Time (Unit:minute)
            /// </summary>
            public int ValidTime { get; set; }
    
            /// <summary>
            /// Enaled
            /// </summary>
            public bool Enabled { get; set; }
        }

     3、 KeyManager.cs

    负责访问Key配置的XML文件,并将其缓存到静态Hashtable中,使用时直接从中检索到要用的信息,设置监听程序FileSystemWatcher如果文件发生变动则重置Hashtable使其重新读取,配置文件及名称可以自行变更或配置

    还要提供根据KeyName获取Key配置对象的方法,这样就可以使用Key存到实际的缓存中,如果Key需要进行构造还可以传送Key的标识数组,从此方法中自动整合返回

        /// <summary>
        /// 缓存Key管理
        /// Author:taiyonghai
        /// CreateTime:2017-08-28
        /// </summary>
        public static class KeyManager
        {
            //KeyName集合
            private static Hashtable keyNameList;
            //锁对象
            private static object objLock = new object();
            //监控文件对象
            private static FileSystemWatcher watcher;
            //缓存Key配置文件路径
            private static readonly string configFilePath = AppDomain.CurrentDomain.SetupInformation.ApplicationBase + "Configs\Cache\";
            //缓存Key配置文件名
            private static readonly string configFileName = "KeyConfigList.xml";
    
            /// <summary>
            /// 静态构造只执行一次
            /// </summary>
            static KeyManager()
            {
                //创建对配置文件夹的监听,如果遇到文件更改则清空KeyNameList,重新读取
                watcher = new FileSystemWatcher();
                watcher.Path = configFilePath;//监听路径
                watcher.Filter = configFileName;//监听文件名
                watcher.NotifyFilter = NotifyFilters.CreationTime | NotifyFilters.LastWrite | NotifyFilters.Size;//仅监听文件创建时间、文件变更时间、文件大小
                watcher.Changed += new FileSystemEventHandler(OnChanged);
                watcher.EnableRaisingEvents = true;//最后开启监听
            }
    
            /// <summary>
            /// 读取KeyName文件
            /// </summary>
            private static void ReaderKeyFile()
            {
                if (keyNameList == null || keyNameList.Count == 0)
                {
                    //锁定读取xml操作
                    lock (objLock)
                    {
                        //获取配置文件
                        string configFile = String.Concat(configFilePath, configFileName);
                        //检查文件
                        if (!File.Exists(configFile))
                        {
                            throw new FileNotFoundException(String.Concat("file not exists:", configFile));
                        }
    
                        //读取xml文件
                        XmlReaderSettings xmlSetting = new XmlReaderSettings();
                        xmlSetting.IgnoreComments = true;//忽略注释
                        XmlReader xmlReader = XmlReader.Create(configFile, xmlSetting);
                        //一次读完整个文档
                        XmlDocument xmlDoc = new XmlDocument();
                        xmlDoc.Load(xmlReader);
                        xmlReader.Close();//关闭读取对象
    
                        //获取指定节点下的所有子节点
                        XmlNodeList nodeList = xmlDoc.SelectSingleNode("//configuration//list").ChildNodes;
    
                        //获得一个线程安全的Hashtable对象
                        keyNameList = Hashtable.Synchronized(new Hashtable());
    
                        //将xml中的属性赋值给Hashtable
                        foreach (XmlNode node in nodeList)
                        {
                            XmlElement element = (XmlElement)node;//转为元素获取属性
    
                            KeyEntity entity = new KeyEntity();
                            entity.Name = element.GetAttribute("name");
                            entity.Key = element.GetAttribute("key");
                            entity.ValidTime = Convert.ToInt32(element.GetAttribute("validTime"));
                            entity.Enabled = Convert.ToBoolean(element.GetAttribute("enabled"));
    
                            keyNameList.Add(entity.Name, entity);
                        }
                    }
                }
            }
    
            /// <summary>
            /// 变更事件会触发两次是正常情况,是系统保存文件机制导致
            /// </summary>
            /// <param name="source"></param>
            /// <param name="e"></param>
            private static void OnChanged(object source, FileSystemEventArgs e)
            {
                if (e.ChangeType == WatcherChangeTypes.Changed)
                {
                    if (e.Name.ToLower() == configFileName.ToLower())
                    {
                        keyNameList = null;
    
                        //因为此事件会被调用两次,所以里面的代码要有幕等性,如果无法实现幕等性,
                        //则应该在Init()中绑定事件
                        //watcher.Changed += new FileSystemEventHandler(OnChanged);
                        //在OnChanged()事件中解绑事件
                        //watcher.Changed -= new FileSystemEventHandler(OnChanged);
                    }
                }
            }
    
            /// <summary>
            /// 根据KeyName获取Key配置对象
            /// </summary>
            /// <param name="name">Key名称</param>
            /// <returns></returns>
            public static KeyEntity Get(KeyNames name)
            {
                return Get(name, null);
            }
            /// <summary>
            /// 根据KeyName获取Key配置对象
            /// </summary>
            /// <param name="name">Key名称</param>
            /// <param name="identities">Key标识(用于替换Key中的{0}占位符)</param>
            /// <returns></returns>
            public static KeyEntity Get(KeyNames name, params string[] identities)
            {
                //检查Hash中是否有值
                if (keyNameList == null || keyNameList.Count == 0)
                    KeyManager.ReaderKeyFile();
                //检查Hash中是否有此Key
                string tmpName = name.ToString().ToLower();
                if (!keyNameList.ContainsKey(tmpName))
                    throw new ArgumentException("keyNameList中不存在此KeyName", "name");
                var entity = keyNameList[tmpName] as KeyEntity;
                //检查Key是否需要含有占位符
                if (entity.Key.IndexOf('{') > 0)
                {
                    //检查参数数组是否有值
                    if (identities != null && identities.Length > 0)
                        entity.Key = String.Format(entity.Key, identities);
                    else
                        throw new ArgumentException("需要此参数identities标识字段,但并未传递", "identities");
                }
                return entity;
            }
    
        }

     4、KeyNames.cs

    用枚举类型是为了控制传递的KeyName能够被限制,不会随便传个string过来导致出错,实际还是使用了KeyNames.Admin_User_Session.ToString()来识别的,此处是根据枚举名查找KeyConfigList.xml中的name属性

        /// <summary>
        /// KeyName枚举(公开)
        /// Author:taiyonghai
        /// CreateTime:2017-08-28
        /// </summary>
        public enum KeyNames
        {
            /// <summary>
            /// 后台用户会话key
            /// </summary>
            Admin_User_Session,
    
            Admin_User_List,
    
            Admin_User_Search
    
        }

     5、RedisManager.cs

    这里可以是Redis也可以是Memcached主要就是提供缓存技术的管理,热门的dll有ServiceStack.Redis和StackExchange.Redis,可前者已经收费(免费使用有使用限额),无限额免费只能用4.0之前的版本,所以采用了后者

    IConnectionMultiplexer是核心对象,此处使用单例模式创建连接对象,因为创建连接的资源消耗较高,后面有测试结果可以证明

    在静态构造中绑定了几个异常事件,如果发生了错误可以写日志便于我们调试使用,GetDatabase()方法很轻量可以放心直接调用,配置文件可以采用其他方式

        /// <summary>
        /// Redis缓存管理类
        /// Author:taiyonghai
        /// CreateTime:2017-08-28
        /// </summary>
        public static class RedisManager
        {
            //Redis连接对象
            private static IConnectionMultiplexer redisMultiplexer;
            //程序锁
            private static object objLock = new object();
            //Redis连接串(多个服务器用逗号隔开)"10.11.12.237:6379, password='',keepalive=300,connecttimeout=5000,synctimeout=1000"
            private static readonly string connectStr = "10.11.12.237:6379";
    
            /// <summary>
            /// 静态构造用于注册监听事件
            /// </summary>
            static RedisManager()
            {
                //注册事件
                GetMultiplexer().ConnectionFailed += ConnectionFailed;
                GetMultiplexer().InternalError += InternalError;
                GetMultiplexer().ErrorMessage += ErrorMessage;
            }
            /// <summary>
            /// 连接失败
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private static void ConnectionFailed(object sender, ConnectionFailedEventArgs e)
            {
                //e.Exception
            }
            /// <summary>
            /// 内部错误
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private static void InternalError(object sender, InternalErrorEventArgs e)
            {
                //e.Exception
            }
            /// <summary>
            /// 发生错误
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private static void ErrorMessage(object sender, RedisErrorEventArgs e)
            {
                //e.Message
            }
            /// <summary>
            /// 获得连接对象
            /// </summary>
            /// <returns></returns>
            private static IConnectionMultiplexer GetMultiplexer()
            {
                if (redisMultiplexer == null || !redisMultiplexer.IsConnected)
                {
                    lock (objLock)
                    {
                        //创建Redis连接对象
                        redisMultiplexer = ConnectionMultiplexer.Connect(connectStr);
                    }
                }
                return redisMultiplexer;
            }
            /// <summary>
            /// 获得客户端对象
            /// </summary>
            /// <param name="db">选填指明使用那个数据库0-16</param>
            /// <returns></returns>
            public static IDatabase GetClient(int db = -1)
            {
                return GetMultiplexer().GetDatabase(db);
            }
    
        }

    如果每次都ConnectionMultiplexer.Connect()一个连接对象的测试结果如下:

    采用单例模式处理连接对象的测试结果如下: 

     6、CacheProvider.cs

    对项目中提供的缓存操作类,提供多个方法,我只提供了String类型和Hash类型,Set集合类型我用不到就没有提供,需要的朋友可以自己添加

        /// <summary>
        /// 缓存提供类
        /// Author:taiyonghai
        /// CreateTime:2017-08-28
        /// </summary>
        public class CacheProvider
        {
            #region Cache 删除
    
            /// <summary>
            /// 删除缓存
            /// </summary>
            /// <param name="name">Key名称</param>
            /// <returns>True成功,Flase失败</returns>
            public bool DelKey(KeyNames name)
            {
                return DelKey(name, null);
            }
            /// <summary>
            /// 删除缓存[核心]
            /// </summary>
            /// <param name="name">Key名称</param>
            /// <param name="identities">Key标识(用于替换Key中的{0}占位符)</param>
            /// <returns>True成功,Flase失败</returns>
            public bool DelKey(KeyNames name, params string[] identities)
            {
                var entity = KeyManager.Get(name, identities);
                return RedisManager.GetClient().KeyDelete(entity.Key);
            }
    
            #endregion
    
            #region Cache String 存取
    
            #region 添加缓存
    
            /// <summary>
            /// 添加缓存,有过期时间(如Key存在则更新值)
            /// </summary>
            /// <param name="name">Key名称</param>
            /// <param name="value">不可为NULL,应对缓存穿透请用空</param>
            /// <returns>True成功,Flase失败</returns>
            public bool SetString<T>(KeyNames name, T value) where T : class, new()
            {
                return SetString<T>(name, value, null);
            }
            /// <summary>
            /// 添加缓存,有过期时间(如Key存在则更新值)
            /// </summary>
            /// <param name="name">Key名称</param>
            /// <param name="value">不可为NULL,应对缓存穿透请用空</param>
            /// <param name="identities">Key标识(用于替换Key中的{0}占位符)</param>
            /// <returns>True成功,Flase失败</returns>
            public bool SetString<T>(KeyNames name, T value, params string[] identities) where T : class, new()
            {
                //如果value为null直接缓存无需序列化
                string tmpStr = null == value ? null : JsonSerializer.SerializeToString<T>(value);
                return SetString(name, tmpStr, identities);
            }
            /// <summary>
            /// 添加缓存,有过期时间(如Key存在则更新值)
            /// </summary>
            /// <param name="name">Key名称</param>
            /// <param name="value">不可为NULL,应对缓存穿透请用空</param>
            /// <returns>True成功,Flase失败</returns>
            public bool SetString(KeyNames name, string value)
            {
                return SetString(name, value, null);
            }
            /// <summary>
            /// 添加缓存,有过期时间[核心](如Key存在则更新值)
            /// </summary>
            /// <param name="name">Key名称</param>
            /// <param name="value">不可为NULL,应对缓存穿透请用空</param>
            /// <param name="identities">Key标识(用于替换Key中的{0}占位符)</param>
            /// <returns>True成功,Flase失败</returns>
            public bool SetString(KeyNames name, string value, params string[] identities)
            {
                //不可传值为NULL,应对缓存穿透请用空,NULL用来判断是否缓存有值
                if (null == value)
                    return false;
                var entity = KeyManager.Get(name, identities);
                //有效时间的TimeSpan=(最小时间+有效时间)-最小时间
                TimeSpan timeSpan = DateTime.MinValue.AddMinutes(entity.ValidTime) - DateTime.MinValue;
                return RedisManager.GetClient().StringSet(entity.Key, value, timeSpan);
            }
    
            #endregion
    
            #region 获取缓存
    
            /// <summary>
            /// 获取缓存
            /// </summary>
            /// <param name="name">Key名称</param>
            /// <returns>无缓存或禁用缓存均返回NULL</returns>
            public T GetString<T>(KeyNames name) where T : class, new()
            {
                return GetString<T>(name, null);
            }
            /// <summary>
            /// 获取缓存
            /// </summary>
            /// <param name="name">Key名称</param>
            /// <param name="identities">Key标识(用于替换Key中的{0}占位符)</param>
            /// <returns>无缓存或禁用缓存均返回NULL</returns>
            public T GetString<T>(KeyNames name, params string[] identities) where T : class, new()
            {
                string tmpStr = GetString(name, identities);
                //如果tmpStr为null直接返回无需反序列化
                return null == tmpStr ? default(T) : JsonSerializer.DeserializeFromString<T>(tmpStr);
            }
            /// <summary>
            /// 获取缓存
            /// </summary>
            /// <param name="name">Key名称</param>
            /// <returns>无缓存或禁用缓存均返回NULL</returns>
            public string GetString(KeyNames name)
            {
                return GetString(name, null);
            }
            /// <summary>
            /// 获取缓存[核心]
            /// </summary>
            /// <param name="name">Key名称</param>
            /// <param name="identities">Key标识(用于替换Key中的{0}占位符)</param>
            /// <returns>无缓存或禁用缓存均返回NULL</returns>
            public string GetString(KeyNames name, params string[] identities)
            {
                var entity = KeyManager.Get(name, identities);
                //检查缓存是否启用,否则返回NULL
                if (entity.Enabled)
                {
                    return RedisManager.GetClient().StringGet(entity.Key);
                }
                else
                {
                    return null;
                }
            }
    
            #endregion
    
            #endregion
    
            #region Cache Hash 存取
    
            #region 添加缓存
    
            /// <summary>
            /// 添加缓存,无过期时间(如Key存在则更新值)
            /// </summary>
            /// <param name="name">Key名称</param>
            /// <param name="dict">不可为NULL,应对缓存穿透请用空对象</param>
            public bool SetHash<T>(KeyNames name, Dictionary<string, T> dict) where T : class, new()
            {
                return SetHash<T>(name, dict, null);
            }
            /// <summary>
            /// 添加缓存,无过期时间(如Key存在则更新值)
            /// </summary>
            /// <param name="name">Key名称</param>
            /// <param name="dict">不可为NULL,应对缓存穿透请用空对象</param>
            /// <param name="identities">Key标识(用于替换Key中的{0}占位符)</param>
            public bool SetHash<T>(KeyNames name, Dictionary<string, T> dict, params string[] identities) where T : class, new()
            {
                var tmpDict = new Dictionary<string, string>();
                foreach (var item in dict)
                    tmpDict.Add(item.Key, null == item.Value ? null : JsonSerializer.SerializeToString<T>(item.Value));
                return SetHash(name, tmpDict, identities);
            }
            /// <summary>
            /// 添加缓存,无过期时间(如Key存在则更新值)
            /// </summary>
            /// <param name="name">Key名称</param>
            /// <param name="dict">不可为NULL,应对缓存穿透请用空对象</param>
            public bool SetHash(KeyNames name, Dictionary<string, string> dict)
            {
                return SetHash(name, dict, null);
            }
            /// <summary>
            /// 添加缓存,无过期时间[核心](如Key存在则更新值)
            /// </summary>
            /// <param name="name">Key名称</param>
            /// <param name="dict">不可为NULL,应对缓存穿透请用空对象</param>
            /// <param name="identities">Key标识(用于替换Key中的{0}占位符)</param>
            public bool SetHash(KeyNames name, Dictionary<string, string> dict, params string[] identities)
            {
                //不可传值为NULL,应对缓存穿透请用空对象,NULL用来判断是否缓存有值
                if (null == dict)
                    return false;
                var entity = KeyManager.Get(name, identities);
                var hashEntryList = new List<HashEntry>();
                foreach (var item in dict)
                    hashEntryList.Add(new HashEntry(item.Key, item.Value));
                RedisManager.GetClient().HashSet(entity.Key, hashEntryList.ToArray());
                return true;
            }
    
            #endregion
    
            #region 获取缓存
    
            /// <summary>
            /// 获取缓存
            /// </summary>
            /// <param name="name">Key名称</param>
            /// <returns>无缓存或禁用缓存均返回NULL</returns>
            public Dictionary<string, T> GetHash<T>(KeyNames name) where T : class, new()
            {
                return GetHash<T>(name, null);
            }
            /// <summary>
            /// 获取缓存
            /// </summary>
            /// <param name="name">Key名称</param>
            /// <param name="identities">Key标识(用于替换Key中的{0}占位符)</param>
            /// <returns>无缓存或禁用缓存均返回NULL</returns>
            public Dictionary<string, T> GetHash<T>(KeyNames name, params string[] identities) where T : class, new()
            {
                var dict = GetHash(name, identities);
                var tmpDict = new Dictionary<string, T>();
                foreach (var item in dict)
                    tmpDict.Add(item.Key, null == item.Value ? default(T) : JsonSerializer.DeserializeFromString<T>(item.Value));
                return tmpDict;
            }
            /// <summary>
            /// 获取缓存
            /// </summary>
            /// <param name="name">Key名称</param>
            /// <returns>无缓存或禁用缓存均返回NULL</returns>
            public Dictionary<string, string> GetHash(KeyNames name)
            {
                return GetHash(name, null);
            }
            /// <summary>
            /// 获取缓存[核心]
            /// </summary>
            /// <param name="name">Key名称</param>
            /// <param name="identities">Key标识(用于替换Key中的{0}占位符)</param>
            /// <returns>无缓存或禁用缓存均返回NULL</returns>
            public Dictionary<string, string> GetHash(KeyNames name, params string[] identities)
            {
                var entity = KeyManager.Get(name, identities);
                //检查缓存是否启用,否则返回NULL
                if (entity.Enabled)
                {
                    var hashEntry = RedisManager.GetClient().HashGetAll(entity.Key);
                    var dict = new Dictionary<string, string>();
                    foreach (var item in hashEntry)
                        dict.Add(item.Name, item.Value);
                    return dict;
                }
                else
                {
                    return null;
                }
            } 
    
            #endregion
    
            #endregion
    
        }
    View Code

     7、MQProvider.cs

    对项目中提供的消息队列操作类,我偷懒应用了Redis的List类型来提供消息队列的操作,少数据量的情况下比如msg在10k以下性能很好,大数据量时性能下降严重,有兴趣可以百度一下看看测试,但他没有事务级的能力所以小规模使用可以,需求高还是需要更专业的队列比如RabbitMQ等

        /// <summary>
        /// 队列提供类
        /// Author:taiyonghai
        /// CreateTime:2017-08-31
        /// </summary>
        public class MQProvider
        {
            #region MQ 添加
    
            /// <summary>
            /// 添加一条消息到队列
            /// </summary>
            /// <param name="name">Key名称</param>
            /// <param name="msg">内容</param>
            /// <returns></returns>
            public long SetMsg<T>(KeyNames name, T msg) where T : class, new()
            {
                return SetMsg<T>(name, msg, null);
            }
            /// <summary>
            /// 添加一条消息到队列
            /// </summary>
            /// <param name="name">Key名称</param>
            /// <param name="msg">内容</param>
            /// <param name="identities">Key标识(用于替换Key中的{0}占位符)</param>
            /// <returns></returns>
            public long SetMsg<T>(KeyNames name, T msg, params string[] identities) where T : class, new()
            {
                //如果value为null直接缓存无需序列化
                string tmpMsg = null == msg ? null : JsonSerializer.SerializeToString<T>(msg);
                return SetMsg(name, tmpMsg, identities);
            }
            /// <summary>
            /// 添加一条消息到队列
            /// </summary>
            /// <param name="name">Key名称</param>
            /// <param name="msg">内容</param>
            /// <returns></returns>
            public long SetMsg(KeyNames name, string msg)
            {
                return SetMsg(name, msg, null);
            }
            /// <summary>
            /// 添加一条消息到队列[核心]
            /// </summary>
            /// <param name="name">Key名称</param>
            /// <param name="msg">内容</param>
            /// <param name="identities">Key标识(用于替换Key中的{0}占位符)</param>
            /// <returns>添加消息后的队列长度</returns>
            public long SetMsg(KeyNames name, string msg, params string[] identities)
            {
                var entity = KeyManager.Get(name, identities);
                //向队列右侧插入新的消息
                return RedisManager.GetClient().ListRightPush(entity.Key, msg);
            }
    
            #endregion
    
            #region MQ 获取
    
            /// <summary>
            /// 从队列中获取一条消息,并将其在队列中移除
            /// </summary>
            /// <param name="name">Key名称</param>
            /// <returns>没有消息返回NULL</returns>
            public T GetMsg<T>(KeyNames name) where T : class, new()
            {
                return GetMsg<T>(name, null);
            }
            /// <summary>
            /// 从队列中获取一条消息,并将其在队列中移除
            /// </summary>
            /// <param name="name">Key名称</param>
            /// <param name="identities">Key标识(用于替换Key中的{0}占位符)</param>
            /// <returns>没有消息返回NULL</returns>
            public T GetMsg<T>(KeyNames name, params string[] identities) where T : class, new()
            {
                string tmpStr = GetMsg(name, identities);
                return null == tmpStr ? default(T) : JsonSerializer.DeserializeFromString<T>(tmpStr);
            }
            /// <summary>
            /// 从队列中获取一条消息,并将其在队列中移除
            /// </summary>
            /// <param name="name">Key名称</param>
            /// <returns>没有消息返回NULL</returns>
            public string GetMsg(KeyNames name)
            {
                return GetMsg(name, null);
            }
            /// <summary>
            /// 从队列中获取一条消息,并将其在队列中移除[核心]
            /// </summary>
            /// <param name="name">Key名称</param>
            /// <param name="identities">Key标识(用于替换Key中的{0}占位符)</param>
            /// <returns>没有消息返回NULL</returns>
            public string GetMsg(KeyNames name, params string[] identities)
            {
                var entity = KeyManager.Get(name, identities);
                //从队列左侧队列头部取出消息
                return RedisManager.GetClient().ListLeftPop(entity.Key);
            }
    
            #endregion
        }
    View Code

      

    三、项目调用代码

    Redis如果遇到同样Key且同类型(String、Hash、List)时是直接覆盖值,如果不同类型的话就会报错了,我偷懒使用了同一个KeyNames就使用加前缀的方式来区分同类型不重复

    CacheProvider cache = new CacheProvider();
    MQProvider mq = new MQProvider();
    //基础类型
    cache.SetString(KeyNames.Cache_Admin_User_Session, "taiyonghai", "100");
    var str = cache.GetString(KeyNames.Cache_Admin_User_Session);
    //Hash类型
    var dict = new Dictionary<string, string>();
    dict.Add("1", "待处理");
    dict.Add("2", "处理中");
    dict.Add("3", "处理完成");
    cache.SetHash(KeyNames.Cache_Hash_Admin_User_List, dict);
    var tmpDict = cache.GetHash(KeyNames.Cache_Hash_Admin_User_List);
    //List队列
    mq.SetMsg(KeyNames.Msg_Admin_User_Search, "Hello");
    mq.GetMsg(KeyNames.Msg_Admin_User_Search);

      

    附录:配置参数解析

  • 相关阅读:
    我败在了盲目和没有计划
    跟我一起学.NetCore目录
    跟我一起学.NetCore之依赖注入作用域和对象释放
    跟我一起学.NetCore之Asp.NetCore启动流程浅析
    std::unordered_map
    Android apps for “armeabi-v7a” and “x86” architecture: SoC vs. Processor vs. ABI
    android studio 配置相关问题
    shell script
    vscode配置
    linux常用命令笔记
  • 原文地址:https://www.cnblogs.com/taiyonghai/p/7464173.html
Copyright © 2011-2022 走看看