Redis緩存項目應用架構設計一

一些項目整理出的項目中引入緩存的架構設計方案,但願能幫助你更好地管理項目緩存,做者水平有限,若有不足還望指點。node

1、基礎結構介紹redis

項目中對外提供方法的是CacheProvider和MQProvider兩個類,一切緩存或隊列應用都從這裏作入口,後期更換緩存或隊列只須要更改後面的提供者便可數據庫

主要結構設計分爲三部分:數組

一、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從這裏集中管理,不會處處都是)ide

二、內部操做(對接的多個緩存實際提供技術好比Redis、Memcached、LocalCache等)函數

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

三、對外提供(對項目中應用緩存提供支持函數,如更改緩存提供技術只需從這裏調整代碼,不影響項目主體代碼)

Cache -> CacheProvider.cs(項目中的緩存操做提供函數類)

MQ -> MQProvider.cs(項目中的隊列操做提供函數類)

 

2、代碼詳細介紹

一、KeyConfigList.xml

用於存儲緩存中數據的Key、有效時間、是否啓用此緩存等配置信息

name:用來尋找此條Key信息的標識

key:緩存中存的Key

validTime:便於計算此緩存的有效時間,好比只緩存5分鐘

enabled:是否啓用此緩存,不啓用則每次都讀庫

{0}、{1}、{2}:緩存Key的佔位符用於區分某個類型的緩存其中的一個,好比商品緩存格式爲Goods:{0},可能實際存儲Key是Goods:一、Goods:二、Goods:3,這個一、二、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>

 二、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; }
    }

 三、 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;
        }

    }

 四、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

    }

 五、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()一個鏈接對象的測試結果以下:

採用單例模式處理鏈接對象的測試結果以下: 

 六、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

 七、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

  

3、項目調用代碼

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

  

附錄:配置參數解析

相關文章
相關標籤/搜索