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

研究了下redis在.net下的使用,因为以前在java上用redis用的是jedis操作,在.net不是很熟悉,在网站上也看了一部分的.net下redis的使用,大部分都是ServiceStack.Redis听说ServiceStack.Redis4.0版本都是收费的,这个我不是很清楚,但是我确实有项目再用ServiceStack.Redis。

这里就不讨论ServiceStack.Redis的使用今天带来的是StackExchange.Redis的封装版。

代码参考

DDD领域驱动之干货(三)完结篇!

下面是干货

RedisCaching里面放着的是Redis的基本5个方法分别如下图所示:

RedisCommon里面放着的是redis的帮助类和初始化类如下图所示:

现在举了例子就以DoRedisStringCache为例:

实现了接口IRedisCaching,当然这里这个接口是标识接口意思就是用来约束的。

StackExchange.Redis是初始化是单列模式,内部有一套自己的方法,这里我就放一下代码

这里面还有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然后是我的数据库

这里是我登录的测试代码:

时间: 2024-10-08 23:07:28

在.Net下使用redis基于StackExchange.Redis的相关文章

怎样在Redis通过StackExchange.Redis 存储集合类型List

StackExchange 是由StackOverFlow出品, 是对Redis的.NET封装,被越来越多的.NET开发者使用在项目中. 绝大部分原先使用ServiceStack的开发者逐渐都转了过来,由于SS在其新版中不再开源,并对免费版本有所限制. 实际问题 那么用.NET的开发者会发现,其根本没有对List类型的存储封装,那么要实现一个类似如下需求:假如我有一个Customer的模型. public class Customer { public string FirstName { ge

Auzre微软云Redis后台StackExchange.Redis使用KeySpaceNotification实现缓存过期前操作/处理一些事件

https://github.com/rustd/RedisSamples/blob/master/HelloWorld/KeySpaceNotifications.cs 懂的可以直接看上面官方提供的demo代码就明白怎么用了 Auzre上面需要设置keyspace notifications with "Kxg" 然后在项目启动的时候订阅,比如使用的是Nancy,就在Boostrapper启动里加上订阅程序 个人示例代码: var db = CacheManager.Connecti

Windows下Redis缓存服务器的使用 .NET StackExchange.Redis Redis Desktop Manager

Redis缓存服务器是一款key/value数据库,读110000次/s,写81000次/s,因为是内存操作所以速度飞快,常见用法是存用户token.短信验证码等 官网显示Redis本身并没有Windows版本的,微软官方开发了基于Windows的Redis服务器:MSOpenTech/redis 一.Redis服务端 首先下载Redis服务器,点击前往下载.msi版本,双击安装Redis服务端就有了,并以服务的形式随系统一起启动: 安装好Redis服务器之后第一件事就是设置密码,进入安装目录:

StackExchange.Redis通用封装类分享

前两天朋友问我,有没有使用过StackExchange.Redis,问我要个封装类,由于之前都是使用ServiceStack.Redis,由于ServiceStack.Redis v4版本后是收费版的,所以现在也很有公司都在使用StackExchange.Redis而抛弃ServiceStack.Redis了.其实个人觉得,两个驱动都不错,只是由于ServiceStack.Redis收费导致目前很多公司都是基于V3版本的使用,也有人说V3版本有很多Bug,没有维护和升级,不过至少目前我是没发现B

Redis学习笔记~StackExchange.Redis实现分布式Session

回到目录 对于多WEB的环境现在已经是必须的了,很难想像一台WEB服务器面对百万并发的响应,所以,我们需要多台WEB服务器集群合作,来缓解这种高并发,高吞吐的场景,而对于多WEB的场景又会有个问题出现,即session存储的问题,如一个用户登陆后,把一个状态信息存储到当前WEB服务器的session里,而你请求其它页面时,很可能就被路由到另一台服务器了,这时,session也就丢了,而对于这种情况,有人把redis这个存储中间件想了起来,对它进行了封装,就有了今天基于redis的session共

在.net Core中使用StackExchange.Redis 2.0

StackExchange.Redis 2.0做了大量的改进包括使用了高性能的IO库System.IO.Pipelines来提升性能以及解决Timeouts问题, 但是在.net Core2.2之前为实现布式缓存和session等引用了Microsoft.AspNetCore.DataProtection.Redis和Microsoft.Extensions.Caching.Redis ,这2个包都要求使用StackExchange.Redis.StrongName但此包已经不再升级. 如果独立

StackExchange.Redis Client

StackExchange.Redis Client 这期我们来看StackExchange.Redis,这是redis 的.net客户端之一.Redis是一个开源的内存数据存储,可以用来做数据库,缓存或者消息代理服务.目前有不少人在使用ServiceStack.Redis这个.net客户端,但是这个的最新版本目前已经变成了商业软件.对于ServiceStack.Redis这种行为,我们没有什么好说的,留给我们的选择是使用低版本的开源版本或者转向其他的客户端. 要说到StackExchange.

StackExchange.Redis 官方文档(一) Basics

基本使用方法: StackExchange.Redis的核心是 StackExchange.Redis 命名空间的 ConnectionMultiplexer 类;它隐藏了多服务器的实现细节.ConnectionMultiplexer被设计成可以在多个客户端之间分享和复用.不用每次操作都创建一个对象实例.对于这种使用方式,它是足够的线程安全和完备的.以后所有的示例都会假设已经创建了一个 ConnectionMultiplexer 实例对象,并且可以存储出来以备复用.但是现在,我们需要创建一个Co

RedisRepository封装—Redis发布订阅以及StackExchange.Redis中的使用

本文版权归博客园和作者本人吴双共同所有,转载请注明本Redis系列分享地址.http://www.cnblogs.com/tdws/tag/NoSql/ Redis Pub/Sub模式 基本介绍 Redis发布订阅—Pub/Sub模式或者说是观察者模式.我想大家即使没有使用过,也已经耳熟能详了. 先简单举例说明下应用场景,在场景中我们可以分析到其优势在哪. 比如你的线上应用应用,你想设置一个日志报警系统,当应用出现异常的时候,立马发送通知给你,可能是短信的形式,也可能是邮件的形式.当然如果只将报