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);

      

    附录:配置参数解析

  • 相关阅读:
    linux下shell显示-bash-4.1#不显示路径解决方法
    update chnroute
    An error "Host key verification failed" when you connect to other computer by OSX SSH
    使用dig查询dns解析
    DNS被污染后
    TunnelBroker for EdgeRouter 后记
    mdadm详细使用手册
    关于尼康黄的原因
    Panda3d code in github
    Python实例浅谈之三Python与C/C++相互调用
  • 原文地址:https://www.cnblogs.com/taiyonghai/p/7464173.html
Copyright © 2011-2022 走看看