详解StackExchange.Redis通用封装类分享

2019-12-30 15:26:17于海丽

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

不过ServiceStack.Redis同StackExchange.Redis比较,抛开收费的来说,确认比StackExchange.Redis 更有优势。StackExchange.Redis文档很少,更不要说国内的文档了,连github上面对应的介绍文档都是很片面,这点我真的觉得StackExchange.Redis的作者至少要完善下文档,很多都是要看源码的例子才有。网上对StackExchange.Redis的使用例子也比ServiceStack.Redis少得多,不是说没人用,只是我查来查去,大部分都是基于String类型的数据进行使用的封装类,对于List,SortedSet,Hash的封装操作都很少,基本都是东写一点,西写一点,很难找到完整的。在参考了一些文章和源码后,这里提供一个自己封装的类,基本提供对于各种类型的使用封装,提供给大家学习使用,如果有哪里写的不好的,大家也可以互相交流。

ConnectionMultiplexer 封装

首先是 ConnectionMultiplexer 的封装,ConnectionMultiplexer对象是StackExchange.Redis最中枢的对象。这个类的实例需要被整个应用程序域共享和重用的,所以不需要在每个操作中不停的创建该对象的实例,一般都是使用单例来创建和存放这个对象,这个在官网上也有说明。


/// <summary>
 /// ConnectionMultiplexer对象管理帮助类
 /// </summary>
 public static class RedisConnectionHelp
 {
  //系统自定义Key前缀
  public static readonly string SysCustomKey = ConfigurationManager.AppSettings["redisKey"] ?? "";

  //"127.0.0.1:6379,allowadmin=true
  private static readonly string RedisConnectionString = ConfigurationManager.ConnectionStrings["RedisExchangeHosts"].ConnectionString;

  private static readonly object Locker = new object();
  private static ConnectionMultiplexer _instance;
  private static readonly ConcurrentDictionary<string, ConnectionMultiplexer> ConnectionCache = new ConcurrentDictionary<string, ConnectionMultiplexer>();

  /// <summary>
  /// 单例获取
  /// </summary>
  public static ConnectionMultiplexer Instance
  {
   get
   {
    if (_instance == null)
    {
     lock (Locker)
     {
      if (_instance == null || !_instance.IsConnected)
      {
       _instance = GetManager();
      }
     }
    }
    return _instance;
   }
  }

  /// <summary>
  /// 缓存获取
  /// </summary>
  /// <param name="connectionString"></param>
  /// <returns></returns>
  public static ConnectionMultiplexer GetConnectionMultiplexer(string connectionString)
  {
   if (!ConnectionCache.ContainsKey(connectionString))
   {
    ConnectionCache[connectionString] = GetManager(connectionString);
   }
   return ConnectionCache[connectionString];
  }

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

   //注册如下事件
   connect.ConnectionFailed += MuxerConnectionFailed;
   connect.ConnectionRestored += MuxerConnectionRestored;
   connect.ErrorMessage += MuxerErrorMessage;
   connect.ConfigurationChanged += MuxerConfigurationChanged;
   connect.HashSlotMoved += MuxerHashSlotMoved;
   connect.InternalError += MuxerInternalError;

   return connect;
  }

  #region 事件

  /// <summary>
  /// 配置更改时
  /// </summary>
  /// <param name="sender"></param>
  /// <param name="e"></param>
  private static void MuxerConfigurationChanged(object sender, EndPointEventArgs e)
  {
   Console.WriteLine("Configuration changed: " + e.EndPoint);
  }

  /// <summary>
  /// 发生错误时
  /// </summary>
  /// <param name="sender"></param>
  /// <param name="e"></param>
  private static void MuxerErrorMessage(object sender, RedisErrorEventArgs e)
  {
   Console.WriteLine("ErrorMessage: " + e.Message);
  }

  /// <summary>
  /// 重新建立连接之前的错误
  /// </summary>
  /// <param name="sender"></param>
  /// <param name="e"></param>
  private static void MuxerConnectionRestored(object sender, ConnectionFailedEventArgs e)
  {
   Console.WriteLine("ConnectionRestored: " + e.EndPoint);
  }

  /// <summary>
  /// 连接失败 , 如果重新连接成功你将不会收到这个通知
  /// </summary>
  /// <param name="sender"></param>
  /// <param name="e"></param>
  private static void MuxerConnectionFailed(object sender, ConnectionFailedEventArgs e)
  {
   Console.WriteLine("重新连接:Endpoint failed: " + e.EndPoint + ", " + e.FailureType + (e.Exception == null ? "" : (", " + e.Exception.Message)));
  }

  /// <summary>
  /// 更改集群
  /// </summary>
  /// <param name="sender"></param>
  /// <param name="e"></param>
  private static void MuxerHashSlotMoved(object sender, HashSlotMovedEventArgs e)
  {
   Console.WriteLine("HashSlotMoved:NewEndPoint" + e.NewEndPoint + ", OldEndPoint" + e.OldEndPoint);
  }

  /// <summary>
  /// redis类库错误
  /// </summary>
  /// <param name="sender"></param>
  /// <param name="e"></param>
  private static void MuxerInternalError(object sender, InternalErrorEventArgs e)
  {
   Console.WriteLine("InternalError:Message" + e.Exception.Message);
  }

  #endregion 事件
 }