在.Net下使用redis基於StackExchange.Redis

研究了下redis在.net下的使用,由於之前在java上用redis用的是jedis操做,在.net不是很熟悉,在網站上也看了一部分的.net下redis的使用,大部分都是ServiceStack.Redis據說ServiceStack.Redis4.0版本都是收費的,這個我不是很清楚,可是我確實有項目再用ServiceStack.Redis。html

這裏就不討論ServiceStack.Redis的使用今天帶來的是StackExchange.Redis的封裝版。java

代碼參考redis

DDD領域驅動之乾貨(三)完結篇!

下面是乾貨數據庫

RedisCaching裏面放着的是Redis的基本5個方法分別以下圖所示:json

RedisCommon裏面放着的是redis的幫助類和初始化類以下圖所示:緩存

如今舉了例子就以DoRedisStringCache爲例:異步

實現了接口IRedisCaching,固然這裏這個接口是標識接口意思就是用來約束的。async

StackExchange.Redis是初始化是單列模式,內部有一套本身的方法,這裏我就放一下代碼post

 

這裏面還有6個事件以下圖:測試

代碼貼出來:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using StackExchange.Redis;
using KuRuMi.Mio.DoMain.Infrastructure.Logger;

namespace KuRuMi.Mio.DoMain.RedisCache.RedisCommon
{
    public class RedisManager
    {
        private static string Constring = RedisConfig.Config();
        private static readonly object locker = new object();
        private static ConnectionMultiplexer instance;
        private static readonly Dictionary<string, ConnectionMultiplexer> Concache = new Dictionary<string, ConnectionMultiplexer>();

        /// <summary>
        /// 單例模式獲取redis鏈接實例
        /// </summary>
        public static ConnectionMultiplexer Instance
        {
            get
            {
                if (instance == null)
                {
                    lock (locker)
                    {
                        if (instance == null)
                            instance = GetManager();
                    }
                }
                return instance;
            }
        }

        /// <summary>
        /// 從緩存中獲取
        /// </summary>
        /// <param name="constr"></param>
        /// <returns></returns>
        public static ConnectionMultiplexer GetConForMap(string constr) {
            if (!Concache.ContainsKey(constr))
                Concache[constr] = GetManager(constr);
            return Concache[constr];
        }

        private static ConnectionMultiplexer GetManager(string constr = null)
        {
            constr = constr ?? Constring;
            var connect = ConnectionMultiplexer.Connect(constr);

            #region 註冊事件
            connect.ConnectionFailed += MuxerConnectionFailed;
            connect.ConnectionRestored += MuxerConnectionRestored;
            connect.ErrorMessage += MuxerErrorMessage;
            connect.ConfigurationChanged += MuxerConfigurationChanged;
            connect.HashSlotMoved += MuxerHashSlotMoved;
            connect.InternalError += MuxerInternalError;
            #endregion

            return connect;
        }
        #region Redis事件
        /// <summary>
        /// 內部異常
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private static void MuxerInternalError(object sender, InternalErrorEventArgs e)
        {
            Units.Log("內部異常:" + e.Exception.Message);
        }

        /// <summary>
        /// 集羣更改
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private static void MuxerHashSlotMoved(object sender, HashSlotMovedEventArgs e)
        {
            Units.Log("新集羣:" + e.NewEndPoint + "舊集羣:" + e.OldEndPoint);
        }

        /// <summary>
        /// 配置更改事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private static void MuxerConfigurationChanged(object sender, EndPointEventArgs e)
        {
            Units.Log("配置更改:" + e.EndPoint);
        }

        /// <summary>
        /// 錯誤事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private static void MuxerErrorMessage(object sender, RedisErrorEventArgs e)
        {
            Units.Log("異常信息:" + e.Message);
        }

        /// <summary>
        /// 重連錯誤事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private static void MuxerConnectionRestored(object sender, ConnectionFailedEventArgs e)
        {
            Units.Log("重連錯誤" + e.EndPoint);
        }

        /// <summary>
        /// 鏈接失敗事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private static void MuxerConnectionFailed(object sender, ConnectionFailedEventArgs e)
        {
            Units.Log("鏈接異常" + e.EndPoint + ",類型爲" + e.FailureType + (e.Exception == null ? "" : (",異常信息是" + e.Exception.Message)));
        }
        #endregion
    }
}

下面是redis的config:

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace KuRuMi.Mio.DoMain.RedisCache.RedisCommon
{
    public sealed class RedisConfig
    {
        public static readonly string config = ConfigurationManager.AppSettings["RedisConfig"];
        public static readonly string redisKey = ConfigurationManager.AppSettings["RedisKey"] ?? "";
        public static string Config() {
            return config;
        }
        public static string Key() {
            return redisKey;
        }
    }
}

下面是redis的helper:

using Newtonsoft.Json;
using StackExchange.Redis;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace KuRuMi.Mio.DoMain.RedisCache.RedisCommon
{
    public class RedisBase
    {
        private static ConnectionMultiplexer db = null;
        private static string key = string.Empty;

        private int DbNumber { get; }
        public RedisBase(int dbnum = 0) : this(dbnum, null)
        {

        }

        public RedisBase(int dbnum, string connectionString)
        {
            DbNumber = dbnum;
            db = string.IsNullOrWhiteSpace(connectionString) ? RedisManager.Instance : RedisManager.GetConForMap(connectionString);
        }

        #region 輔助方法
        /// <summary>
        /// 添加名稱
        /// </summary>
        /// <param name="old"></param>
        /// <returns></returns>
        public string AddKey(string old)
        {
            var fixkey = key ?? RedisConfig.Key();
            return fixkey + old;
        }

        /// <summary>
        /// 執行保存
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="func"></param>
        /// <returns></returns>
        public T DoSave<T>(Func<IDatabase, T> func)
        {
            return func(db.GetDatabase(DbNumber));
        }
        public string ConvertJson<T>(T val)
        {
            return val is string ? val.ToString() : JsonConvert.SerializeObject(val);
        }

        public T ConvertObj<T>(RedisValue val)
        {
            return JsonConvert.DeserializeObject<T>(val);
        }

        public List<T> ConvertList<T>(RedisValue[] val)
        {
            List<T> result = new List<T>();
            foreach (var item in val)
            {
                var model = ConvertObj<T>(item);
                result.Add(model);
            }
            return result;
        }

        public RedisKey[] ConvertRedisKeys(List<string> val)
        {
            return val.Select(k => (RedisKey)k).ToArray();
        }
        #endregion
    }
}

下面是個人string封裝方法:

using KuRuMi.Mio.DoMain.RedisCache.RedisCommon;
using StackExchange.Redis;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace KuRuMi.Mio.DoMain.RedisCache.RedisCaching
{
    /// <summary>
    /// 表示string的操做
    /// </summary>
    public class DoRedisStringCache : IRedisCaching
    {
        private RedisBase redis = null;
        public DoRedisStringCache()
        {
            redis = new RedisBase();
        }

        #region 同步執行
        /// <summary>
        /// 單個保存
        /// </summary>
        /// <param name="key"></param>
        /// <param name="val"></param>
        /// <param name="exp">過時時間</param>
        /// <returns></returns>
        public bool StringSet(string key, string val, TimeSpan? exp = default(TimeSpan?))
        {
            key = redis.AddKey(key);
            return redis.DoSave(db => db.StringSet(key, val, exp));
        }

        /// <summary>
        /// 保存多個key value
        /// </summary>
        /// <param name="keyValues">鍵值對</param>
        /// <returns></returns>
        public bool StringSet(List<KeyValuePair<RedisKey, RedisValue>> KeyVal)
        {
            List<KeyValuePair<RedisKey, RedisValue>> newkey = KeyVal.Select(k => new KeyValuePair<RedisKey, RedisValue>(redis.AddKey(k.Key), k.Value)).ToList();
            return redis.DoSave(db => db.StringSet(newkey.ToArray()));
        }

        /// <summary>
        /// 保存一個對象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="obj"></param>
        /// <param name="exp"></param>
        /// <returns></returns>
        public bool StringSet<T>(string key, T obj, TimeSpan? exp = default(TimeSpan?))
        {
            key = redis.AddKey(key);
            string json = redis.ConvertJson(obj);
            return redis.DoSave(db => db.StringSet(key, json, exp));
        }

        /// <summary>
        /// 獲取單個
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public string StringGet(string key)
        {
           key = redis.AddKey(key);
            return redis.DoSave(db => db.StringGet(key));
        }
        /// <summary>
        /// 獲取單個對象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <returns></returns>
        public T StringGet<T>(string key) {
            key = redis.AddKey(key);
            var val = redis.DoSave(db => db.StringGet(key));
            return redis.ConvertObj<T>(val);
        }

        /// <summary>
        /// 爲數字增加val
        /// </summary>
        /// <param name="key"></param>
        /// <param name="val">能夠爲負數</param>
        /// <returns>增加後的值</returns>
        public double StringIncrement(string key, double val = 1)
        {
           key = redis.AddKey(key);
            return redis.DoSave(db => db.StringIncrement(key, val));
        }
        /// <summary>
        /// 爲數字減小val
        /// </summary>
        /// <param name="key"></param>
        /// <param name="val">能夠爲負數</param>
        /// <returns>增加後的值</returns>
        public double StringDecrement(string key, double val = 1)
        {
           key = redis.AddKey(key);
            return redis.DoSave(db => db.StringDecrement(key, val));
        }
        #endregion

        #region 異步執行
        /// <summary>
        /// 異步保存單個
        /// </summary>
        /// <param name="key"></param>
        /// <param name="val"></param>
        /// <param name="exp"></param>
        /// <returns></returns>
        public async Task<bool> StringSetAsync(string key, string val, TimeSpan? exp = default(TimeSpan?))
        {
            key = redis.AddKey(key);
            return await redis.DoSave(db => db.StringSetAsync(key, val, exp));
        }
        /// <summary>
        /// 異步保存多個key value
        /// </summary>
        /// <param name="keyValues">鍵值對</param>
        /// <returns></returns>
        public async Task<bool> StringSetAsync(List<KeyValuePair<RedisKey, RedisValue>> KeyVal)
        {
            List<KeyValuePair<RedisKey, RedisValue>> newkey = KeyVal.Select(k => new KeyValuePair<RedisKey, RedisValue>(redis.AddKey(k.Key), k.Value)).ToList();
            return await redis.DoSave(db => db.StringSetAsync(newkey.ToArray()));
        }

        /// <summary>
        /// 異步保存一個對象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="obj"></param>
        /// <param name="exp"></param>
        /// <returns></returns>
        public async Task<bool> StringSetAsync<T>(string key, T obj, TimeSpan? exp = default(TimeSpan?))
        {
            key = redis.AddKey(key);
            string json = redis.ConvertJson(obj);
            return await redis.DoSave(db => db.StringSetAsync(key, json, exp));
        }

        /// <summary>
        /// 異步獲取單個
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public async Task<string> StringGetAsync(string key)
        {
           key = redis.AddKey(key);
            return await redis.DoSave(db => db.StringGetAsync(key));
        }

        /// <summary>
        /// 異步獲取單個
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public async Task<T> StringGetAsync<T>(string key)
        {
            key = redis.AddKey(key);
            var val = await redis.DoSave(db => db.StringGetAsync(key));
            return redis.ConvertObj<T>(val);
        }

        /// <summary>
        /// 異步爲數字增加val
        /// </summary>
        /// <param name="key"></param>
        /// <param name="val">能夠爲負數</param>
        /// <returns>增加後的值</returns>
        public async Task<double> StringIncrementAsync(string key, double val = 1)
        {
           key = redis.AddKey(key);
            return await redis.DoSave(db => db.StringIncrementAsync(key, val));
        }
        /// <summary>
        /// 爲數字減小val
        /// </summary>
        /// <param name="key"></param>
        /// <param name="val">能夠爲負數</param>
        /// <returns>增加後的值</returns>
        public async Task<double> StringDecrementAsync(string key, double val = 1)
        {
           key = redis.AddKey(key);
            return await redis.DoSave(db => db.StringDecrementAsync(key, val));
        }
        #endregion
    }
}

StackExchange.Redis自己提供了一套異步的方法這個我比較喜歡。至於其餘的和string的同理,我這裏就不放出封裝方法,須要的留言。

最後是測試:

這是個人redis而後是個人數據庫

這裏是我登陸的測試代碼:

相關文章
相關標籤/搜索