zoukankan      html  css  js  c++  java
  • Redis分布式队列和缓存更新

      原文链接:https://www.cnblogs.com/hua66/p/9600085.html

      在使用Redis中,我们可能会遇到以下场景:

      例如:

      某用户向服务器中发送一个请求,服务器将用户请求加入Redis任务队列,任务完成则移出队列。

      以上场景有几点疑问:

    1. Redis队列中数据如果不仅仅来自于我们的应用程序,那么我们怎么把这个数据加入Redis?
    2. 当Redis队列中用户的请求达程序所能处理的峰值。那么我们该如何处理这些用户请求?

      解决方案:

    1.  对外提供接口,将请求数据添加至DB。启动一个定时服务,在规定时间扫描DB中的请求数据并添加至Redis队列。
    2. 使用分布式异步队列。

      以上解决方案都可以使用插件来实现。

    1. 使用Quartz.Net
    2. 使用StackExchange.Redis

      一、

      关于Quartz.Net可以通过上面链接获取官方API。它与SQL Server中的代理作业有着同样功能。

      代码示例:

      

     1  /// <summary>
     2         /// 添加Job并以周期的形式运行
     3         /// </summary>
     4         /// <typeparam name="T"></typeparam>
     5         /// <param name="jobName">job名称</param>
     6         /// <param name="jobGroupName">job组名称</param>
     7         /// <param name="replace">job是否可修改</param>
     8         /// <param name="triggerName">job触发器的名称</param>
     9         /// <param name="minutes">job执行的时间间隔,以分为单位</param>
    10         /// <returns></returns>
    11         public DateTimeOffset AddJob<T>(string jobName, string jobGroupName, bool replace, string triggerName, int minutes) where T : IJob
    12         {
    13             IJobDetail jobDetail = JobBuilder.Create<T>().WithIdentity(jobName, jobGroupName).Build();
    14             _sched.AddJob(jobDetail, replace);
    15             ITrigger trigger = TriggerBuilder.Create()
    16               .WithIdentity(triggerName, jobGroupName)
    17               .StartNow()
    18               .WithSimpleSchedule(x => x
    19                   .WithIntervalInMinutes(minutes)//表示分钟的时间间隔
    20                   .RepeatForever())
    21               .Build();
    22             return _sched.ScheduleJob(jobDetail, trigger).Result;
    23         }
    View Code

      以上的代码中是基于Quartz封装一个添加了Job的方法。这个方法依赖于 “IJobDetail” 和 “ITrigger” 这两个对象。

      “IJobDetail” 表示Job的身份信息,“ITrigger” 则包含了Job执行信息,它表示Job该如何执行。

      以下为调用示例:

      

    1 QuartzHelper quartzHelper = QuartzHelper.CreateInstance();
    2                 quartzHelper.AddJob<TestJob>("testJob", "testJob_Group",false, "testJob_Trigger",1*10);
    View Code

      上述实例中的 “TestJob” 实现Quartz.Net中的 "IJob" 接口。这个接口只有一个方法 “Execute”,并由Quartz.Net框架自行调用该方法。

      你可以在此方法中执行你的代码。并在添加该Job制定你的执行策略 “ITrigger” 对象。然后框架会根据你制定的策略进行调用。调用参数请参见上述封装。

      下面是向Redis队列插入数据的示例Job:

      

     1 public class TestJob : IJob
     2     {
     3         Task IJob.Execute(IJobExecutionContext context)
     4         {
     5             //JobDataMap dataMap = context.JobDetail.JobDataMap;
     6             Task task = Task.Run(
     7                   () =>
     8                   {
     9                       Console.WriteLine(string.Format("{0}开始执行!当前系统时间{1}", this.GetType().Name, DateTime.Now));
    10                       try
    11                       {
    12                           string redisKey = this.GetType().Name;
    13                           RedisHelper redisHelper = new RedisHelper();
    14                           if (redisHelper.KeyExists(redisKey))
    15                           {
    16                               redisHelper.KeyDelete(redisKey);
    17                           };
    18 
    19                           for (int i = 1; i <= 10; i++)
    20                           {
    21                               User user = new User()
    22                               {
    23                                   ID = i,
    24                                   Name = "user" + DateTime.Now.Ticks +"_"+ i                                  
    25                               };
    26                               redisHelper.ListLeftPush<User>(redisKey, user);//模拟DB用户数据
    27                           }
    28                       }
    29                       catch (Exception ex)
    30                       {
    31                           Console.WriteLine(string.Format("{0}任务出现异常,异常信息:{1}!当前系统时间{2}", this.GetType().Name, ex.Message, DateTime.Now));
    32                       }
    33                   }
    34                   );
    35             return task;
    36         }
    37     }
    View Code

      上面的 “TestJob” 模拟了从DB加载用户请求数据至Redis队列。至此我们已经解决了上面的第一个问题。

      二、

      在.Net中Redis的插件不多。比较流行有 "ServiceStack.Redis" 和 "StackExchange.Redis" 。

      "ServiceStack.Redis" 为官方推出的插件。非开源插件,且普通版最高只支持 6000/S 读写。高级版是要收费的。为了后续扩展,这里我们采用 "StackExchange.Redis" 。

      关于StackExchange.Redis可以通过上面链接获取官方API,目前是开源的。

      在第一个问题中,已经通过定时Job的方式向Redis队列中填充数据。下面我们通过 "StackExchange.Redis" 获取Redis队列中的请求并处理这些请求。

      1.加载数据至Redis:

      

     1 using APP_Test.Job;
     2 using Common.Quartz;
     3 using Common.Redis.StackExchange;
     4 using Quartz;
     5 using System;
     6 using System.Collections.Generic;
     7 using System.Linq;
     8 using System.Text;
     9 using System.Threading.Tasks;
    10 
    11 namespace APP_Test
    12 {
    13     class Program
    14     {
    15         static void Main(string[] args)
    16         {
    17             {
    18                 RedisHelper redisHelperA = new RedisHelper();
    19                 RedisHelper redisHelperB = new RedisHelper();
    20                 string stra = redisHelperA.StringGet("mykey");
    21                 string strb = redisHelperB.StringGet("mykey");
    22                 if (stra== strb)
    23                 {
    24                     Console.WriteLine(string.Format("***********{0}=={1}***********", stra, strb));
    25                 }
    26                 else
    27                 {
    28                     Console.WriteLine(string.Format("***********{0}!={1}***********", stra, strb));
    29                 }
    30             }
    31 
    32             {
    33                 
    34                 QuartzHelper quartzHelper = QuartzHelper.CreateInstance();
    35                 quartzHelper.AddJob<TestJob>("testJob", "testJob_Group",false, "testJob_Trigger",1*10);//这里设置了以秒为单位
    36             }
    37 
    38             Console.ReadKey();
    39         }
    40         
    41     }
    42 }
    View Code

      

      可以看到上面代码执行的时间节点与我们所添加job中的 ”ITrigger “ 的触发策略完全一致。至此,我们第一步已得到验证。

      2.启动处理Redis队列中请求的程序。

      

     1 using APP_Test.Models;
     2 using Common.Redis.StackExchange;
     3 using System;
     4 using System.Collections.Generic;
     5 using System.Linq;
     6 using System.Text;
     7 using System.Threading.Tasks;
     8 
     9 namespace APP_RedisClientTest
    10 {
    11     class Program
    12     {
    13         static void Main(string[] args)
    14         {
    15             RedisHelper redisHelper = new RedisHelper();
    16             string redisKey = "TestJob";
    17             while (true)
    18             {
    19                 Action action = new Action(() =>
    20                 {
    21                     User user = redisHelper.ListLeftPop<User>(redisKey);//获取请求数据并移出队列
    22                     if (user!=null)
    23                     {
    24                         Console.WriteLine(string.Format("*******{0}*******", user.Name));
    25                     }                    
    26                 }
    27                     );
    28                 action.EndInvoke(action.BeginInvoke(null, null));
    29             }
    30             Console.ReadKey();
    31         }
    32     }
    33 }
    View Code

      

      上面我启动3个客户端实例,他们一起处理Redis队列中的请求。每当Job向Redis队列中添加请求对象后就会立即被我们处理请求的程序获取并消费,每当一个请求被消费就会被移出Redis队列。并且遵循先入先出的准则。按照上述,如果出现主程序请求量过高情形,我们只需要启动多个处理请求的辅助程序即可缓解主程序的压力。

      至此上面的两个问题已得到验证。

      如下附个人基于 "Quartz.Net" 和 "StackExchange.Redis" 封装的帮助类

      

      1 using System;
      2 using System.Collections.Generic;
      3 
      4 namespace Common.Quartz
      5 {
      6     using global::Quartz;
      7     using global::Quartz.Impl;
      8     using global::Quartz.Impl.Matchers;
      9 
     10     /// <summary>
     11     /// V:3.0.6.0
     12     /// </summary>
     13     public class QuartzHelper
     14     {
     15         private readonly static object _obj = new object();//单例锁
     16 
     17         //private  ISchedulerFactory _sf = null;
     18 
     19         private static IScheduler _sched = null;
     20         /// <summary>
     21         /// 提供IScheduler对象,访问异步方法
     22         /// </summary>
     23         public IScheduler Scheduler { get { return _sched; } }
     24 
     25         private static QuartzHelper _quartzHelper = null;//单例对象
     26 
     27         private QuartzHelper()
     28         {
     29             //_sf = new StdSchedulerFactory();
     30             //_sched = _sf.GetScheduler().Result;
     31             _sched = StdSchedulerFactory.GetDefaultScheduler().Result;
     32             _sched.Start();
     33         }
     34 
     35         /// <summary>
     36         /// 获取单例对象
     37         /// </summary>
     38         /// <returns></returns>
     39         public static QuartzHelper CreateInstance()
     40         {
     41             if (_quartzHelper == null) //双if +lock
     42             {
     43                 lock (_obj)
     44                 {
     45                     if (_quartzHelper == null)
     46                     {
     47                         _quartzHelper = new QuartzHelper();
     48                     }
     49                 }
     50             }
     51             return _quartzHelper;
     52         }
     53         public bool CheckExists(TriggerKey triggerKey)
     54         {
     55             return _sched.CheckExists(triggerKey).Result;
     56         }
     57         public bool CheckExists(JobKey jobKey)
     58         {
     59             return _sched.CheckExists(jobKey).Result;
     60         }
     61         public IReadOnlyCollection<IJobExecutionContext> GetCurrentlyExecutingJobs()
     62         {
     63             return _sched.GetCurrentlyExecutingJobs().Result;
     64         }
     65 
     66         /// <summary>
     67         /// 添加Job并以周期的形式运行
     68         /// </summary>
     69         /// <typeparam name="T"></typeparam>
     70         /// <param name="jobName">job名称</param>
     71         /// <param name="jobGroupName">job组名称</param>
     72         /// <param name="replace">job是否可修改</param>
     73         /// <param name="triggerName">job触发器的名称</param>
     74         /// <param name="minutes">job执行的时间间隔,以分为单位</param>
     75         /// <returns></returns>
     76         public DateTimeOffset AddJob<T>(string jobName, string jobGroupName, bool replace, string triggerName, int minutes) where T : IJob
     77         {
     78             IJobDetail jobDetail = JobBuilder.Create<T>().WithIdentity(jobName, jobGroupName).Build();
     79             _sched.AddJob(jobDetail, replace);
     80             ITrigger trigger = TriggerBuilder.Create()
     81               .WithIdentity(triggerName, jobGroupName)
     82               .StartNow()
     83               .WithSimpleSchedule(x => x
     84                   .WithIntervalInSeconds(minutes)//seconds表示秒的时间间隔
     85                                                  //.WithIntervalInMinutes(minutes)//表示分钟的时间间隔
     86                   .RepeatForever())
     87               .Build();
     88             return _sched.ScheduleJob(jobDetail, trigger).Result;
     89         }
     90         public bool DeleteJobs(IReadOnlyCollection<JobKey> jobKeys)
     91         {
     92             return _sched.DeleteJobs(jobKeys).Result;
     93         }
     94         public IJobDetail GetJobDetail(JobKey jobKey)
     95         {
     96             return _sched.GetJobDetail(jobKey).Result;
     97         }
     98         public IReadOnlyCollection<string> GetJobGroupNames()
     99         {
    100             return _sched.GetJobGroupNames().Result;
    101         }
    102         public IReadOnlyCollection<JobKey> GetJobKeys(GroupMatcher<JobKey> matcher)
    103         {
    104             return _sched.GetJobKeys(matcher).Result;
    105         }
    106         public bool Interrupt(JobKey jobKey)
    107         {
    108             return _sched.Interrupt(jobKey).Result;
    109         }
    110         public bool IsJobGroupPaused(string groupName)
    111         {
    112             return _sched.IsJobGroupPaused(groupName).Result;
    113         }
    114         public ITrigger GetTrigger(TriggerKey triggerKey)
    115         {
    116             return _sched.GetTrigger(triggerKey).Result;
    117         }
    118         public IReadOnlyCollection<string> GetTriggerGroupNames()
    119         {
    120             return _sched.GetTriggerGroupNames().Result;
    121         }
    122         public IReadOnlyCollection<TriggerKey> GetTriggerKeys(GroupMatcher<TriggerKey> matcher)
    123         {
    124             return _sched.GetTriggerKeys(matcher).Result;
    125         }
    126         public IReadOnlyCollection<ITrigger> GetTriggersOfJob(JobKey jobKey)
    127         {
    128             return _sched.GetTriggersOfJob(jobKey).Result;
    129         }
    130         public TriggerState GetTriggerState(TriggerKey triggerKey)
    131         {
    132             return _sched.GetTriggerState(triggerKey).Result;
    133         }
    134         public IReadOnlyCollection<string> GetPausedTriggerGroups()
    135         {
    136             return _sched.GetPausedTriggerGroups().Result;
    137         }
    138         public bool Interrupt(string fireInstanceId)
    139         {
    140             return _sched.Interrupt(fireInstanceId).Result;
    141         }
    142         public bool IsTriggerGroupPaused(string groupName)
    143         {
    144             return _sched.IsTriggerGroupPaused(groupName).Result;
    145         }
    146         public void PauseAll()
    147         {
    148             _sched.PauseAll();
    149         }
    150         public void PauseJobs(GroupMatcher<JobKey> matcher)
    151         {
    152             _sched.PauseJobs(matcher);
    153         }
    154         public void PauseTriggers(GroupMatcher<TriggerKey> matcher)
    155         {
    156             _sched.PauseTriggers(matcher);
    157         }
    158         public void ResumeAll()
    159         {
    160             _sched.ResumeAll();
    161         }
    162         public void ResumeJobs(GroupMatcher<JobKey> matcher)
    163         {
    164             _sched.ResumeJobs(matcher);
    165         }
    166         public void ResumeTriggers(GroupMatcher<TriggerKey> matcher)
    167         {
    168             _sched.ResumeTriggers(matcher);
    169         }
    170         public void ScheduleJobs(IReadOnlyDictionary<IJobDetail, IReadOnlyCollection<ITrigger>> triggersAndJobs, bool replace)
    171         {
    172             _sched.ScheduleJobs(triggersAndJobs, replace);
    173         }
    174         public DateTimeOffset? RescheduleJob(TriggerKey triggerKey, ITrigger newTrigger)
    175         {
    176             return _sched.RescheduleJob(triggerKey, newTrigger).Result;
    177         }
    178         public void Shutdown(bool waitForJobsToComplete)
    179         {
    180             _sched.Shutdown(waitForJobsToComplete);
    181         }
    182         public void Clear()
    183         {
    184             _sched.Clear();
    185         }
    186 
    187 
    188     }
    189 }
    View Code
       1 using StackExchange.Redis;
       2 using System;
       3 using System.Collections.Generic;
       4 using System.Configuration;
       5 using System.IO;
       6 using System.Linq;
       7 using System.Runtime.Serialization.Formatters.Binary;
       8 using System.Threading.Tasks;
       9 using Newtonsoft.Json;
      10 
      11 namespace Common.Redis.StackExchange
      12 {
      13     /// <summary>
      14     /// V:1.2.6.0
      15     /// </summary>
      16     public class RedisHelper
      17     {
      18         #region private field
      19 
      20         /// <summary>
      21         /// 连接字符串
      22         /// </summary>
      23         private static readonly string ConnectionString;
      24 
      25         /// <summary>
      26         /// redis 连接对象
      27         /// </summary>
      28         private static IConnectionMultiplexer _connMultiplexer;
      29 
      30         /// <summary>
      31         /// 默认的 Key 值(用来当作 RedisKey 的前缀)
      32         /// </summary>
      33         private static readonly string DefaultKey;
      34 
      35         /// <summary>
      36         ///  37         /// </summary>
      38         private static readonly object Locker = new object();
      39 
      40         /// <summary>
      41         /// 数据库
      42         /// </summary>
      43         private readonly IDatabase _db;
      44 
      45         #endregion private field
      46 
      47         #region 构造函数
      48 
      49         static RedisHelper()
      50         {
      51             ConnectionString = ConfigurationManager.ConnectionStrings["RedisConnectionString"].ConnectionString;
      52             _connMultiplexer = ConnectionMultiplexer.Connect(ConnectionString);
      53             DefaultKey = ConfigurationManager.AppSettings["Redis.DefaultKey"];
      54             AddRegisterEvent();
      55         }
      56 
      57         public RedisHelper(int db = 0)
      58         {
      59             _db = _connMultiplexer.GetDatabase(db);
      60         }
      61 
      62         #endregion 构造函数
      63 
      64         #region 其它
      65 
      66         /// <summary>
      67         /// 获取 Redis 连接对象
      68         /// </summary>
      69         /// <returns></returns>
      70         public IConnectionMultiplexer GetConnectionRedisMultiplexer()
      71         {
      72             if (_connMultiplexer == null || !_connMultiplexer.IsConnected)
      73                 lock (Locker)
      74                 {
      75                     if (_connMultiplexer == null || !_connMultiplexer.IsConnected)
      76                         _connMultiplexer = ConnectionMultiplexer.Connect(ConnectionString);
      77                 }
      78 
      79             return _connMultiplexer;
      80         }
      81 
      82         public ITransaction GetTransaction()
      83         {
      84             return _db.CreateTransaction();
      85         }
      86 
      87         #endregion 其它
      88 
      89         #region 类型封装
      90 
      91         #region String 操作
      92 
      93         /// <summary>
      94         /// 设置 key 并保存字符串(如果 key 已存在,则覆盖值)
      95         /// </summary>
      96         /// <param name="redisKey"></param>
      97         /// <param name="redisValue"></param>
      98         /// <param name="expiry"></param>
      99         /// <returns></returns>
     100         public bool StringSet(string redisKey, string redisValue, TimeSpan? expiry = null)
     101         {
     102             redisKey = AddKeyPrefix(redisKey);
     103             return _db.StringSet(redisKey, redisValue, expiry);
     104         }
     105 
     106         /// <summary>
     107         /// 保存多个 Key-value
     108         /// </summary>
     109         /// <param name="keyValuePairs"></param>
     110         /// <returns></returns>
     111         public bool StringSet(IEnumerable<KeyValuePair<string, string>> keyValuePairs)
     112         {
     113             var pairs = keyValuePairs.Select(x => new KeyValuePair<RedisKey, RedisValue>(AddKeyPrefix(x.Key), x.Value));
     114             return _db.StringSet(pairs.ToArray());
     115         }
     116 
     117         /// <summary>
     118         /// 获取字符串
     119         /// </summary>
     120         /// <param name="redisKey"></param>
     121         /// <param name="expiry"></param>
     122         /// <returns></returns>
     123         public string StringGet(string redisKey, TimeSpan? expiry = null)
     124         {
     125             redisKey = AddKeyPrefix(redisKey);
     126             return _db.StringGet(redisKey);
     127         }
     128 
     129         /// <summary>
     130         /// 存储一个对象(该对象会被序列化保存)
     131         /// </summary>
     132         /// <param name="redisKey"></param>
     133         /// <param name="redisValue"></param>
     134         /// <param name="expiry"></param>
     135         /// <returns></returns>
     136         public bool StringSet<T>(string redisKey, T redisValue, TimeSpan? expiry = null)
     137         {
     138             redisKey = AddKeyPrefix(redisKey);
     139             var json = Serialize(redisValue);
     140             return _db.StringSet(redisKey, json, expiry);
     141         }
     142 
     143         /// <summary>
     144         /// 获取一个对象(会进行反序列化)
     145         /// </summary>
     146         /// <param name="redisKey"></param>
     147         /// <param name="expiry"></param>
     148         /// <returns></returns>
     149         public T StringGet<T>(string redisKey, TimeSpan? expiry = null)
     150         {
     151             redisKey = AddKeyPrefix(redisKey);
     152             return Deserialize<T>(_db.StringGet(redisKey));
     153         }
     154 
     155         #region async
     156 
     157         /// <summary>
     158         /// 保存一个字符串值
     159         /// </summary>
     160         /// <param name="redisKey"></param>
     161         /// <param name="redisValue"></param>
     162         /// <param name="expiry"></param>
     163         /// <returns></returns>
     164         public async Task<bool> StringSetAsync(string redisKey, string redisValue, TimeSpan? expiry = null)
     165         {
     166             redisKey = AddKeyPrefix(redisKey);
     167             return await _db.StringSetAsync(redisKey, redisValue, expiry);
     168         }
     169 
     170         /// <summary>
     171         /// 保存一组字符串值
     172         /// </summary>
     173         /// <param name="keyValuePairs"></param>
     174         /// <returns></returns>
     175         public async Task<bool> StringSetAsync(IEnumerable<KeyValuePair<string, string>> keyValuePairs)
     176         {
     177             var pairs = keyValuePairs.Select(x => new KeyValuePair<RedisKey, RedisValue>(AddKeyPrefix(x.Key), x.Value));
     178             return await _db.StringSetAsync(pairs.ToArray());
     179         }
     180 
     181         /// <summary>
     182         /// 获取单个值
     183         /// </summary>
     184         /// <param name="redisKey"></param>
     185         /// <param name="redisValue"></param>
     186         /// <param name="expiry"></param>
     187         /// <returns></returns>
     188         public async Task<string> StringGetAsync(string redisKey, string redisValue, TimeSpan? expiry = null)
     189         {
     190             redisKey = AddKeyPrefix(redisKey);
     191             return await _db.StringGetAsync(redisKey);
     192         }
     193 
     194         /// <summary>
     195         /// 存储一个对象(该对象会被序列化保存)
     196         /// </summary>
     197         /// <param name="redisKey"></param>
     198         /// <param name="redisValue"></param>
     199         /// <param name="expiry"></param>
     200         /// <returns></returns>
     201         public async Task<bool> StringSetAsync<T>(string redisKey, T redisValue, TimeSpan? expiry = null)
     202         {
     203             redisKey = AddKeyPrefix(redisKey);
     204             var json = Serialize(redisValue);
     205             return await _db.StringSetAsync(redisKey, json, expiry);
     206         }
     207 
     208         /// <summary>
     209         /// 获取一个对象(会进行反序列化)
     210         /// </summary>
     211         /// <param name="redisKey"></param>
     212         /// <param name="expiry"></param>
     213         /// <returns></returns>
     214         public async Task<T> StringGetAsync<T>(string redisKey, TimeSpan? expiry = null)
     215         {
     216             redisKey = AddKeyPrefix(redisKey);
     217             return Deserialize<T>(await _db.StringGetAsync(redisKey));
     218         }
     219 
     220         #endregion async
     221 
     222         #endregion String 操作
     223 
     224         #region Hash 操作
     225 
     226         /// <summary>
     227         /// 判断该字段是否存在 hash 中
     228         /// </summary>
     229         /// <param name="redisKey"></param>
     230         /// <param name="hashField"></param>
     231         /// <returns></returns>
     232         public bool HashExists(string redisKey, string hashField)
     233         {
     234             redisKey = AddKeyPrefix(redisKey);
     235             return _db.HashExists(redisKey, hashField);
     236         }
     237 
     238         /// <summary>
     239         /// 从 hash 中移除指定字段
     240         /// </summary>
     241         /// <param name="redisKey"></param>
     242         /// <param name="hashField"></param>
     243         /// <returns></returns>
     244         public bool HashDelete(string redisKey, string hashField)
     245         {
     246             redisKey = AddKeyPrefix(redisKey);
     247             return _db.HashDelete(redisKey, hashField);
     248         }
     249 
     250         /// <summary>
     251         /// 从 hash 中移除指定字段
     252         /// </summary>
     253         /// <param name="redisKey"></param>
     254         /// <param name="hashFields"></param>
     255         /// <returns></returns>
     256         public long HashDelete(string redisKey, IEnumerable<string> hashFields)
     257         {
     258             redisKey = AddKeyPrefix(redisKey);
     259             var fields = hashFields.Select(x => (RedisValue)x);
     260 
     261             return _db.HashDelete(redisKey, fields.ToArray());
     262         }
     263 
     264         /// <summary>
     265         /// 在 hash 设定值
     266         /// </summary>
     267         /// <param name="redisKey"></param>
     268         /// <param name="hashField"></param>
     269         /// <param name="value"></param>
     270         /// <returns></returns>
     271         public bool HashSet(string redisKey, string hashField, string value)
     272         {
     273             redisKey = AddKeyPrefix(redisKey);
     274             return _db.HashSet(redisKey, hashField, value);
     275         }
     276 
     277         /// <summary>
     278         /// 在 hash 中设定值
     279         /// </summary>
     280         /// <param name="redisKey"></param>
     281         /// <param name="hashFields"></param>
     282         public void HashSet(string redisKey, IEnumerable<KeyValuePair<string, string>> hashFields)
     283         {
     284             redisKey = AddKeyPrefix(redisKey);
     285             var entries = hashFields.Select(x => new HashEntry(x.Key, x.Value));
     286 
     287             _db.HashSet(redisKey, entries.ToArray());
     288         }
     289 
     290         /// <summary>
     291         /// 在 hash 中获取值
     292         /// </summary>
     293         /// <param name="redisKey"></param>
     294         /// <param name="hashField"></param>
     295         /// <returns></returns>
     296         public string HashGet(string redisKey, string hashField)
     297         {
     298             redisKey = AddKeyPrefix(redisKey);
     299             return _db.HashGet(redisKey, hashField);
     300         }
     301 
     302         /// <summary>
     303         /// 在 hash 中获取值
     304         /// </summary>
     305         /// <param name="redisKey"></param>
     306         /// <param name="hashFields"></param>
     307         /// <returns></returns>
     308         public IEnumerable<string> HashGet(string redisKey, IEnumerable<string> hashFields)
     309         {
     310             redisKey = AddKeyPrefix(redisKey);
     311             var fields = hashFields.Select(x => (RedisValue)x);
     312 
     313             return ConvertStrings(_db.HashGet(redisKey, fields.ToArray()));
     314         }
     315 
     316         /// <summary>
     317         /// 从 hash 返回所有的字段值
     318         /// </summary>
     319         /// <param name="redisKey"></param>
     320         /// <returns></returns>
     321         public IEnumerable<string> HashKeys(string redisKey)
     322         {
     323             redisKey = AddKeyPrefix(redisKey);
     324             return ConvertStrings(_db.HashKeys(redisKey));
     325         }
     326 
     327         /// <summary>
     328         /// 返回 hash 中的所有值
     329         /// </summary>
     330         /// <param name="redisKey"></param>
     331         /// <returns></returns>
     332         public IEnumerable<string> HashValues(string redisKey)
     333         {
     334             redisKey = AddKeyPrefix(redisKey);
     335             return ConvertStrings(_db.HashValues(redisKey));
     336         }
     337 
     338         /// <summary>
     339         /// 在 hash 设定值(序列化)
     340         /// </summary>
     341         /// <param name="redisKey"></param>
     342         /// <param name="hashField"></param>
     343         /// <param name="redisValue"></param>
     344         /// <returns></returns>
     345         public bool HashSet<T>(string redisKey, string hashField, T redisValue)
     346         {
     347             redisKey = AddKeyPrefix(redisKey);
     348             var json = Serialize(redisValue);
     349 
     350             return _db.HashSet(redisKey, hashField, json);
     351         }
     352 
     353         /// <summary>
     354         /// 在 hash 中获取值(反序列化)
     355         /// </summary>
     356         /// <param name="redisKey"></param>
     357         /// <param name="hashField"></param>
     358         /// <returns></returns>
     359         public T HashGet<T>(string redisKey, string hashField)
     360         {
     361             redisKey = AddKeyPrefix(redisKey);
     362 
     363             return Deserialize<T>(_db.HashGet(redisKey, hashField));
     364         }
     365 
     366         #region async
     367 
     368         /// <summary>
     369         /// 判断该字段是否存在 hash 中
     370         /// </summary>
     371         /// <param name="redisKey"></param>
     372         /// <param name="hashField"></param>
     373         /// <returns></returns>
     374         public async Task<bool> HashExistsAsync(string redisKey, string hashField)
     375         {
     376             redisKey = AddKeyPrefix(redisKey);
     377             return await _db.HashExistsAsync(redisKey, hashField);
     378         }
     379 
     380         /// <summary>
     381         /// 从 hash 中移除指定字段
     382         /// </summary>
     383         /// <param name="redisKey"></param>
     384         /// <param name="hashField"></param>
     385         /// <returns></returns>
     386         public async Task<bool> HashDeleteAsync(string redisKey, string hashField)
     387         {
     388             redisKey = AddKeyPrefix(redisKey);
     389             return await _db.HashDeleteAsync(redisKey, hashField);
     390         }
     391 
     392         /// <summary>
     393         /// 从 hash 中移除指定字段
     394         /// </summary>
     395         /// <param name="redisKey"></param>
     396         /// <param name="hashFields"></param>
     397         /// <returns></returns>
     398         public async Task<long> HashDeleteAsync(string redisKey, IEnumerable<string> hashFields)
     399         {
     400             redisKey = AddKeyPrefix(redisKey);
     401             var fields = hashFields.Select(x => (RedisValue)x);
     402 
     403             return await _db.HashDeleteAsync(redisKey, fields.ToArray());
     404         }
     405 
     406         /// <summary>
     407         /// 在 hash 设定值
     408         /// </summary>
     409         /// <param name="redisKey"></param>
     410         /// <param name="hashField"></param>
     411         /// <param name="value"></param>
     412         /// <returns></returns>
     413         public async Task<bool> HashSetAsync(string redisKey, string hashField, string value)
     414         {
     415             redisKey = AddKeyPrefix(redisKey);
     416             return await _db.HashSetAsync(redisKey, hashField, value);
     417         }
     418 
     419         /// <summary>
     420         /// 在 hash 中设定值
     421         /// </summary>
     422         /// <param name="redisKey"></param>
     423         /// <param name="hashFields"></param>
     424         public async Task HashSetAsync(string redisKey, IEnumerable<KeyValuePair<string, string>> hashFields)
     425         {
     426             redisKey = AddKeyPrefix(redisKey);
     427             var entries = hashFields.Select(x => new HashEntry(AddKeyPrefix(x.Key), x.Value));
     428             await _db.HashSetAsync(redisKey, entries.ToArray());
     429         }
     430 
     431         /// <summary>
     432         /// 在 hash 中获取值
     433         /// </summary>
     434         /// <param name="redisKey"></param>
     435         /// <param name="hashField"></param>
     436         /// <returns></returns>
     437         public async Task<string> HashGetAsync(string redisKey, string hashField)
     438         {
     439             redisKey = AddKeyPrefix(redisKey);
     440             return await _db.HashGetAsync(redisKey, hashField);
     441         }
     442 
     443         /// <summary>
     444         /// 在 hash 中获取值
     445         /// </summary>
     446         /// <param name="redisKey"></param>
     447         /// <param name="hashFields"></param>
     448         /// <param name="value"></param>
     449         /// <returns></returns>
     450         public async Task<IEnumerable<string>> HashGetAsync(string redisKey, IEnumerable<string> hashFields,
     451             string value)
     452         {
     453             redisKey = AddKeyPrefix(redisKey);
     454             var fields = hashFields.Select(x => (RedisValue)x);
     455 
     456             return ConvertStrings(await _db.HashGetAsync(redisKey, fields.ToArray()));
     457         }
     458 
     459         /// <summary>
     460         /// 从 hash 返回所有的字段值
     461         /// </summary>
     462         /// <param name="redisKey"></param>
     463         /// <returns></returns>
     464         public async Task<IEnumerable<string>> HashKeysAsync(string redisKey)
     465         {
     466             redisKey = AddKeyPrefix(redisKey);
     467             return ConvertStrings(await _db.HashKeysAsync(redisKey));
     468         }
     469 
     470         /// <summary>
     471         /// 返回 hash 中的所有值
     472         /// </summary>
     473         /// <param name="redisKey"></param>
     474         /// <returns></returns>
     475         public async Task<IEnumerable<string>> HashValuesAsync(string redisKey)
     476         {
     477             redisKey = AddKeyPrefix(redisKey);
     478             return ConvertStrings(await _db.HashValuesAsync(redisKey));
     479         }
     480 
     481         /// <summary>
     482         /// 在 hash 设定值(序列化)
     483         /// </summary>
     484         /// <param name="redisKey"></param>
     485         /// <param name="hashField"></param>
     486         /// <param name="value"></param>
     487         /// <returns></returns>
     488         public async Task<bool> HashSetAsync<T>(string redisKey, string hashField, T value)
     489         {
     490             redisKey = AddKeyPrefix(redisKey);
     491             var json = Serialize(value);
     492             return await _db.HashSetAsync(redisKey, hashField, json);
     493         }
     494 
     495         /// <summary>
     496         /// 在 hash 中获取值(反序列化)
     497         /// </summary>
     498         /// <param name="redisKey"></param>
     499         /// <param name="hashField"></param>
     500         /// <returns></returns>
     501         public async Task<T> HashGetAsync<T>(string redisKey, string hashField)
     502         {
     503             redisKey = AddKeyPrefix(redisKey);
     504             return Deserialize<T>(await _db.HashGetAsync(redisKey, hashField));
     505         }
     506 
     507         #endregion async
     508 
     509         #endregion Hash 操作
     510 
     511         #region List 操作
     512 
     513         /// <summary>
     514         /// 移除并返回存储在该键列表的第一个元素
     515         /// </summary>
     516         /// <param name="redisKey"></param>
     517         /// <returns></returns>
     518         public string ListLeftPop(string redisKey)
     519         {
     520             redisKey = AddKeyPrefix(redisKey);
     521             return _db.ListLeftPop(redisKey);
     522         }
     523 
     524         /// <summary>
     525         /// 移除并返回存储在该键列表的最后一个元素
     526         /// </summary>
     527         /// <param name="redisKey"></param>
     528         /// <returns></returns>
     529         public string ListRightPop(string redisKey)
     530         {
     531             redisKey = AddKeyPrefix(redisKey);
     532             return _db.ListRightPop(redisKey);
     533         }
     534 
     535         /// <summary>
     536         /// 移除列表指定键上与该值相同的元素
     537         /// </summary>
     538         /// <param name="redisKey"></param>
     539         /// <param name="redisValue"></param>
     540         /// <returns></returns>
     541         public long ListRemove(string redisKey, string redisValue)
     542         {
     543             redisKey = AddKeyPrefix(redisKey);
     544             return _db.ListRemove(redisKey, redisValue);
     545         }
     546 
     547         /// <summary>
     548         /// 在列表尾部插入值。如果键不存在,先创建再插入值
     549         /// </summary>
     550         /// <param name="redisKey"></param>
     551         /// <param name="redisValue"></param>
     552         /// <returns></returns>
     553         public long ListRightPush(string redisKey, string redisValue)
     554         {
     555             redisKey = AddKeyPrefix(redisKey);
     556             return _db.ListRightPush(redisKey, redisValue);
     557         }
     558 
     559         /// <summary>
     560         /// 在列表头部插入值。如果键不存在,先创建再插入值
     561         /// </summary>
     562         /// <param name="redisKey"></param>
     563         /// <param name="redisValue"></param>
     564         /// <returns></returns>
     565         public long ListLeftPush(string redisKey, string redisValue)
     566         {
     567             redisKey = AddKeyPrefix(redisKey);
     568             return _db.ListLeftPush(redisKey, redisValue);
     569         }
     570 
     571         /// <summary>
     572         /// 返回列表上该键的长度,如果不存在,返回 0
     573         /// </summary>
     574         /// <param name="redisKey"></param>
     575         /// <returns></returns>
     576         public long ListLength(string redisKey)
     577         {
     578             redisKey = AddKeyPrefix(redisKey);
     579             return _db.ListLength(redisKey);
     580         }
     581 
     582         /// <summary>
     583         /// 返回在该列表上键所对应的元素
     584         /// </summary>
     585         /// <param name="redisKey"></param>
     586         /// <param name="start"></param>
     587         /// <param name="stop"></param>
     588         /// <returns></returns>
     589         public IEnumerable<string> ListRange(string redisKey, long start = 0L, long stop = -1L)
     590         {
     591             redisKey = AddKeyPrefix(redisKey);
     592             return ConvertStrings(_db.ListRange(redisKey, start, stop));
     593         }
     594 
     595         /// <summary>
     596         /// 移除并返回存储在该键列表的第一个元素
     597         /// </summary>
     598         /// <param name="redisKey"></param>
     599         /// <returns></returns>
     600         public T ListLeftPop<T>(string redisKey)
     601         {
     602             redisKey = AddKeyPrefix(redisKey);
     603             return Deserialize<T>(_db.ListLeftPop(redisKey));
     604         }
     605 
     606         /// <summary>
     607         /// 移除并返回存储在该键列表的最后一个元素
     608         /// </summary>
     609         /// <param name="redisKey"></param>
     610         /// <returns></returns>
     611         public T ListRightPop<T>(string redisKey)
     612         {
     613             redisKey = AddKeyPrefix(redisKey);
     614             return Deserialize<T>(_db.ListRightPop(redisKey));
     615         }
     616 
     617         /// <summary>
     618         /// 在列表尾部插入值。如果键不存在,先创建再插入值
     619         /// </summary>
     620         /// <param name="redisKey"></param>
     621         /// <param name="redisValue"></param>
     622         /// <returns></returns>
     623         public long ListRightPush<T>(string redisKey, T redisValue)
     624         {
     625             redisKey = AddKeyPrefix(redisKey);
     626             return _db.ListRightPush(redisKey, Serialize(redisValue));
     627         }
     628 
     629         /// <summary>
     630         /// 在列表头部插入值。如果键不存在,先创建再插入值
     631         /// </summary>
     632         /// <param name="redisKey"></param>
     633         /// <param name="redisValue"></param>
     634         /// <returns></returns>
     635         public long ListLeftPush<T>(string redisKey, T redisValue)
     636         {
     637             redisKey = AddKeyPrefix(redisKey);
     638             return _db.ListLeftPush(redisKey, Serialize(redisValue));
     639         }
     640 
     641         #region List-async
     642 
     643         /// <summary>
     644         /// 移除并返回存储在该键列表的第一个元素
     645         /// </summary>
     646         /// <param name="redisKey"></param>
     647         /// <returns></returns>
     648         public async Task<string> ListLeftPopAsync(string redisKey)
     649         {
     650             redisKey = AddKeyPrefix(redisKey);
     651             return await _db.ListLeftPopAsync(redisKey);
     652         }
     653 
     654         /// <summary>
     655         /// 移除并返回存储在该键列表的最后一个元素
     656         /// </summary>
     657         /// <param name="redisKey"></param>
     658         /// <returns></returns>
     659         public async Task<string> ListRightPopAsync(string redisKey)
     660         {
     661             redisKey = AddKeyPrefix(redisKey);
     662             return await _db.ListRightPopAsync(redisKey);
     663         }
     664 
     665         /// <summary>
     666         /// 移除列表指定键上与该值相同的元素
     667         /// </summary>
     668         /// <param name="redisKey"></param>
     669         /// <param name="redisValue"></param>
     670         /// <returns></returns>
     671         public async Task<long> ListRemoveAsync(string redisKey, string redisValue)
     672         {
     673             redisKey = AddKeyPrefix(redisKey);
     674             return await _db.ListRemoveAsync(redisKey, redisValue);
     675         }
     676 
     677         /// <summary>
     678         /// 在列表尾部插入值。如果键不存在,先创建再插入值
     679         /// </summary>
     680         /// <param name="redisKey"></param>
     681         /// <param name="redisValue"></param>
     682         /// <returns></returns>
     683         public async Task<long> ListRightPushAsync(string redisKey, string redisValue)
     684         {
     685             redisKey = AddKeyPrefix(redisKey);
     686             return await _db.ListRightPushAsync(redisKey, redisValue);
     687         }
     688 
     689         /// <summary>
     690         /// 在列表头部插入值。如果键不存在,先创建再插入值
     691         /// </summary>
     692         /// <param name="redisKey"></param>
     693         /// <param name="redisValue"></param>
     694         /// <returns></returns>
     695         public async Task<long> ListLeftPushAsync(string redisKey, string redisValue)
     696         {
     697             redisKey = AddKeyPrefix(redisKey);
     698             return await _db.ListLeftPushAsync(redisKey, redisValue);
     699         }
     700 
     701         /// <summary>
     702         /// 返回列表上该键的长度,如果不存在,返回 0
     703         /// </summary>
     704         /// <param name="redisKey"></param>
     705         /// <returns></returns>
     706         public async Task<long> ListLengthAsync(string redisKey)
     707         {
     708             redisKey = AddKeyPrefix(redisKey);
     709             return await _db.ListLengthAsync(redisKey);
     710         }
     711 
     712         /// <summary>
     713         /// 返回在该列表上键所对应的元素
     714         /// </summary>
     715         /// <param name="redisKey"></param>
     716         /// <param name="start"></param>
     717         /// <param name="stop"></param>
     718         /// <returns></returns>
     719         public async Task<IEnumerable<string>> ListRangeAsync(string redisKey, long start = 0L, long stop = -1L)
     720         {
     721             redisKey = AddKeyPrefix(redisKey);
     722             var query = await _db.ListRangeAsync(redisKey, start, stop);
     723             return query.Select(x => x.ToString());
     724         }
     725 
     726         /// <summary>
     727         /// 移除并返回存储在该键列表的第一个元素
     728         /// </summary>
     729         /// <param name="redisKey"></param>
     730         /// <returns></returns>
     731         public async Task<T> ListLeftPopAsync<T>(string redisKey)
     732         {
     733             redisKey = AddKeyPrefix(redisKey);
     734             return Deserialize<T>(await _db.ListLeftPopAsync(redisKey));
     735         }
     736 
     737         /// <summary>
     738         /// 移除并返回存储在该键列表的最后一个元素
     739         /// </summary>
     740         /// <param name="redisKey"></param>
     741         /// <returns></returns>
     742         public async Task<T> ListRightPopAsync<T>(string redisKey)
     743         {
     744             redisKey = AddKeyPrefix(redisKey);
     745             return Deserialize<T>(await _db.ListRightPopAsync(redisKey));
     746         }
     747 
     748         /// <summary>
     749         /// 在列表尾部插入值。如果键不存在,先创建再插入值
     750         /// </summary>
     751         /// <param name="redisKey"></param>
     752         /// <param name="redisValue"></param>
     753         /// <returns></returns>
     754         public async Task<long> ListRightPushAsync<T>(string redisKey, T redisValue)
     755         {
     756             redisKey = AddKeyPrefix(redisKey);
     757             return await _db.ListRightPushAsync(redisKey, Serialize(redisValue));
     758         }
     759 
     760         /// <summary>
     761         /// 在列表头部插入值。如果键不存在,先创建再插入值
     762         /// </summary>
     763         /// <param name="redisKey"></param>
     764         /// <param name="redisValue"></param>
     765         /// <returns></returns>
     766         public async Task<long> ListLeftPushAsync<T>(string redisKey, T redisValue)
     767         {
     768             redisKey = AddKeyPrefix(redisKey);
     769             return await _db.ListLeftPushAsync(redisKey, Serialize(redisValue));
     770         }
     771 
     772         #endregion List-async
     773 
     774         #endregion List 操作
     775 
     776         #region SortedSet 操作
     777 
     778         /// <summary>
     779         /// SortedSet 新增
     780         /// </summary>
     781         /// <param name="redisKey"></param>
     782         /// <param name="member"></param>
     783         /// <param name="score"></param>
     784         /// <returns></returns>
     785         public bool SortedSetAdd(string redisKey, string member, double score)
     786         {
     787             redisKey = AddKeyPrefix(redisKey);
     788             return _db.SortedSetAdd(redisKey, member, score);
     789         }
     790 
     791         /// <summary>
     792         /// 在有序集合中返回指定范围的元素,默认情况下从低到高。
     793         /// </summary>
     794         /// <param name="redisKey"></param>
     795         /// <param name="start"></param>
     796         /// <param name="stop"></param>
     797         /// <param name="order"></param>
     798         /// <returns></returns>
     799         public IEnumerable<string> SortedSetRangeByRank(string redisKey, long start = 0L, long stop = -1L,
     800             Order order = Order.Ascending)
     801         {
     802             redisKey = AddKeyPrefix(redisKey);
     803             return _db.SortedSetRangeByRank(redisKey, start, stop, (Order)order).Select(x => x.ToString());
     804         }
     805 
     806         /// <summary>
     807         /// 返回有序集合的元素个数
     808         /// </summary>
     809         /// <param name="redisKey"></param>
     810         /// <returns></returns>
     811         public long SortedSetLength(string redisKey)
     812         {
     813             redisKey = AddKeyPrefix(redisKey);
     814             return _db.SortedSetLength(redisKey);
     815         }
     816 
     817         /// <summary>
     818         /// 返回有序集合的元素个数
     819         /// </summary>
     820         /// <param name="redisKey"></param>
     821         /// <param name="memebr"></param>
     822         /// <returns></returns>
     823         public bool SortedSetLength(string redisKey, string memebr)
     824         {
     825             redisKey = AddKeyPrefix(redisKey);
     826             return _db.SortedSetRemove(redisKey, memebr);
     827         }
     828 
     829         /// <summary>
     830         /// SortedSet 新增
     831         /// </summary>
     832         /// <param name="redisKey"></param>
     833         /// <param name="member"></param>
     834         /// <param name="score"></param>
     835         /// <returns></returns>
     836         public bool SortedSetAdd<T>(string redisKey, T member, double score)
     837         {
     838             redisKey = AddKeyPrefix(redisKey);
     839             var json = Serialize(member);
     840 
     841             return _db.SortedSetAdd(redisKey, json, score);
     842         }
     843 
     844         /// <summary>
     845         /// 增量的得分排序的集合中的成员存储键值键按增量
     846         /// </summary>
     847         /// <param name="redisKey"></param>
     848         /// <param name="member"></param>
     849         /// <param name="value"></param>
     850         /// <returns></returns>
     851         public double SortedSetIncrement(string redisKey, string member, double value = 1)
     852         {
     853             redisKey = AddKeyPrefix(redisKey);
     854             return _db.SortedSetIncrement(redisKey, member, value);
     855         }
     856 
     857         #region SortedSet-Async
     858 
     859         /// <summary>
     860         /// SortedSet 新增
     861         /// </summary>
     862         /// <param name="redisKey"></param>
     863         /// <param name="member"></param>
     864         /// <param name="score"></param>
     865         /// <returns></returns>
     866         public async Task<bool> SortedSetAddAsync(string redisKey, string member, double score)
     867         {
     868             redisKey = AddKeyPrefix(redisKey);
     869             return await _db.SortedSetAddAsync(redisKey, member, score);
     870         }
     871 
     872         /// <summary>
     873         /// 在有序集合中返回指定范围的元素,默认情况下从低到高。
     874         /// </summary>
     875         /// <param name="redisKey"></param>
     876         /// <returns></returns>
     877         public async Task<IEnumerable<string>> SortedSetRangeByRankAsync(string redisKey)
     878         {
     879             redisKey = AddKeyPrefix(redisKey);
     880             return ConvertStrings(await _db.SortedSetRangeByRankAsync(redisKey));
     881         }
     882 
     883         /// <summary>
     884         /// 返回有序集合的元素个数
     885         /// </summary>
     886         /// <param name="redisKey"></param>
     887         /// <returns></returns>
     888         public async Task<long> SortedSetLengthAsync(string redisKey)
     889         {
     890             redisKey = AddKeyPrefix(redisKey);
     891             return await _db.SortedSetLengthAsync(redisKey);
     892         }
     893 
     894         /// <summary>
     895         /// 返回有序集合的元素个数
     896         /// </summary>
     897         /// <param name="redisKey"></param>
     898         /// <param name="memebr"></param>
     899         /// <returns></returns>
     900         public async Task<bool> SortedSetRemoveAsync(string redisKey, string memebr)
     901         {
     902             redisKey = AddKeyPrefix(redisKey);
     903             return await _db.SortedSetRemoveAsync(redisKey, memebr);
     904         }
     905 
     906         /// <summary>
     907         /// SortedSet 新增
     908         /// </summary>
     909         /// <param name="redisKey"></param>
     910         /// <param name="member"></param>
     911         /// <param name="score"></param>
     912         /// <returns></returns>
     913         public async Task<bool> SortedSetAddAsync<T>(string redisKey, T member, double score)
     914         {
     915             redisKey = AddKeyPrefix(redisKey);
     916             var json = Serialize(member);
     917 
     918             return await _db.SortedSetAddAsync(redisKey, json, score);
     919         }
     920 
     921         /// <summary>
     922         /// 增量的得分排序的集合中的成员存储键值键按增量
     923         /// </summary>
     924         /// <param name="redisKey"></param>
     925         /// <param name="member"></param>
     926         /// <param name="value"></param>
     927         /// <returns></returns>
     928         public Task<double> SortedSetIncrementAsync(string redisKey, string member, double value = 1)
     929         {
     930             redisKey = AddKeyPrefix(redisKey);
     931             return _db.SortedSetIncrementAsync(redisKey, member, value);
     932         }
     933 
     934         #endregion SortedSet-Async
     935 
     936         #endregion SortedSet 操作
     937 
     938         #endregion 类型封装
     939 
     940         #region 将object序列化读写
     941         public void ListSet<T>(string key, List<T> value)
     942         {
     943             foreach (var single in value)
     944             {
     945                 var jsonobj = JsonConvert.SerializeObject(single); //序列化
     946                 this.ListLeftPush(key, jsonobj); //要一个个的插入
     947                 
     948             }
     949         }
     950         public List<T> ListGet<T>(string key)
     951         {
     952             var jsonArr = this.ListRange(key);
     953             List<T> result = new List<T>();
     954             foreach (var item in jsonArr)
     955             {
     956                 var model = JsonConvert.DeserializeObject<T>(item); //反序列化
     957                 result.Add(model);
     958             }
     959             return result;
     960         }
     961         #endregion
     962 
     963         #region KEY 操作
     964 
     965         /// <summary>
     966         /// 删除单个key
     967         /// </summary>
     968         /// <param name="redisKey"></param>
     969         /// <returns>是否删除成功</returns>
     970         public bool KeyDelete(string redisKey)
     971         {
     972             redisKey = AddKeyPrefix(redisKey);
     973             return _db.KeyDelete(redisKey);
     974         }
     975 
     976         /// <summary>
     977         /// 删除多个key
     978         /// </summary>
     979         /// <param name="redisKeys"></param>
     980         /// <returns>成功删除的个数</returns>
     981         public long KeyDelete(IEnumerable<string> redisKeys)
     982         {
     983             var keys = redisKeys.Select(x => (RedisKey)AddKeyPrefix(x));
     984             return _db.KeyDelete(keys.ToArray());
     985         }
     986 
     987         /// <summary>
     988         /// 校验 Key 是否存在
     989         /// </summary>
     990         /// <param name="redisKey"></param>
     991         /// <returns></returns>
     992         public bool KeyExists(string redisKey)
     993         {
     994             redisKey = AddKeyPrefix(redisKey);
     995             return _db.KeyExists(redisKey);
     996         }
     997 
     998         /// <summary>
     999         /// 重命名 Key
    1000         /// </summary>
    1001         /// <param name="redisKey"></param>
    1002         /// <param name="redisNewKey"></param>
    1003         /// <returns></returns>
    1004         public bool KeyRename(string redisKey, string redisNewKey)
    1005         {
    1006             redisKey = AddKeyPrefix(redisKey);
    1007             return _db.KeyRename(redisKey, redisNewKey);
    1008         }
    1009 
    1010         /// <summary>
    1011         /// 设置 Key 的时间
    1012         /// </summary>
    1013         /// <param name="redisKey"></param>
    1014         /// <param name="expiry"></param>
    1015         /// <returns></returns>
    1016         public bool KeyExpire(string redisKey, TimeSpan? expiry)
    1017         {
    1018             redisKey = AddKeyPrefix(redisKey);
    1019             return _db.KeyExpire(redisKey, expiry);
    1020         }
    1021 
    1022         #region key-async
    1023 
    1024         /// <summary>
    1025         /// 移除指定 Key
    1026         /// </summary>
    1027         /// <param name="redisKey"></param>
    1028         /// <returns></returns>
    1029         public async Task<bool> KeyDeleteAsync(string redisKey)
    1030         {
    1031             redisKey = AddKeyPrefix(redisKey);
    1032             return await _db.KeyDeleteAsync(redisKey);
    1033         }
    1034 
    1035         /// <summary>
    1036         /// 移除指定 Key
    1037         /// </summary>
    1038         /// <param name="redisKeys"></param>
    1039         /// <returns></returns>
    1040         public async Task<long> KeyDeleteAsync(IEnumerable<string> redisKeys)
    1041         {
    1042             var keys = redisKeys.Select(x => (RedisKey)AddKeyPrefix(x));
    1043             return await _db.KeyDeleteAsync(keys.ToArray());
    1044         }
    1045 
    1046         /// <summary>
    1047         /// 校验 Key 是否存在
    1048         /// </summary>
    1049         /// <param name="redisKey"></param>
    1050         /// <returns></returns>
    1051         public async Task<bool> KeyExistsAsync(string redisKey)
    1052         {
    1053             redisKey = AddKeyPrefix(redisKey);
    1054             return await _db.KeyExistsAsync(redisKey);
    1055         }
    1056 
    1057         /// <summary>
    1058         /// 重命名 Key
    1059         /// </summary>
    1060         /// <param name="redisKey"></param>
    1061         /// <param name="redisNewKey"></param>
    1062         /// <returns></returns>
    1063         public async Task<bool> KeyRenameAsync(string redisKey, string redisNewKey)
    1064         {
    1065             redisKey = AddKeyPrefix(redisKey);
    1066             return await _db.KeyRenameAsync(redisKey, redisNewKey);
    1067         }
    1068 
    1069         /// <summary>
    1070         /// 设置 Key 的时间
    1071         /// </summary>
    1072         /// <param name="redisKey"></param>
    1073         /// <param name="expiry"></param>
    1074         /// <returns></returns>
    1075         public async Task<bool> KeyExpireAsync(string redisKey, TimeSpan? expiry)
    1076         {
    1077             redisKey = AddKeyPrefix(redisKey);
    1078             return await _db.KeyExpireAsync(redisKey, expiry);
    1079         }
    1080 
    1081         #endregion key-async
    1082 
    1083         #endregion KEY 操作
    1084 
    1085         #region private method
    1086 
    1087         /// <summary>
    1088         /// 添加 Key 的前缀
    1089         /// </summary>
    1090         /// <param name="key"></param>
    1091         /// <returns></returns>
    1092         private static string AddKeyPrefix(string key)
    1093         {
    1094             return DefaultKey + ":" + key;
    1095         }
    1096 
    1097         /// <summary>
    1098         /// 转换为字符串
    1099         /// </summary>
    1100         /// <typeparam name="T"></typeparam>
    1101         /// <param name="list"></param>
    1102         /// <returns></returns>
    1103         private static IEnumerable<string> ConvertStrings<T>(IEnumerable<T> list) where T : struct
    1104         {
    1105             if (list == null) throw new ArgumentNullException(nameof(list));
    1106             return list.Select(x => x.ToString());
    1107         }
    1108 
    1109         #region 注册事件
    1110 
    1111         /// <summary>
    1112         /// 添加注册事件
    1113         /// </summary>
    1114         private static void AddRegisterEvent()
    1115         {
    1116             _connMultiplexer.ConnectionRestored += ConnMultiplexer_ConnectionRestored;
    1117             _connMultiplexer.ConnectionFailed += ConnMultiplexer_ConnectionFailed;
    1118             _connMultiplexer.ErrorMessage += ConnMultiplexer_ErrorMessage;
    1119             _connMultiplexer.ConfigurationChanged += ConnMultiplexer_ConfigurationChanged;
    1120             _connMultiplexer.HashSlotMoved += ConnMultiplexer_HashSlotMoved;
    1121             _connMultiplexer.InternalError += ConnMultiplexer_InternalError;
    1122             _connMultiplexer.ConfigurationChangedBroadcast += ConnMultiplexer_ConfigurationChangedBroadcast;
    1123         }
    1124 
    1125         /// <summary>
    1126         /// 重新配置广播时(通常意味着主从同步更改)
    1127         /// </summary>
    1128         /// <param name="sender"></param>
    1129         /// <param name="e"></param>
    1130         private static void ConnMultiplexer_ConfigurationChangedBroadcast(object sender, EndPointEventArgs e)
    1131         {
    1132             Console.WriteLine($"{nameof(ConnMultiplexer_ConfigurationChangedBroadcast)}: {e.EndPoint}");
    1133         }
    1134 
    1135         /// <summary>
    1136         /// 发生内部错误时(主要用于调试)
    1137         /// </summary>
    1138         /// <param name="sender"></param>
    1139         /// <param name="e"></param>
    1140         private static void ConnMultiplexer_InternalError(object sender, InternalErrorEventArgs e)
    1141         {
    1142             Console.WriteLine($"{nameof(ConnMultiplexer_InternalError)}: {e.Exception}");
    1143         }
    1144 
    1145         /// <summary>
    1146         /// 更改集群时
    1147         /// </summary>
    1148         /// <param name="sender"></param>
    1149         /// <param name="e"></param>
    1150         private static void ConnMultiplexer_HashSlotMoved(object sender, HashSlotMovedEventArgs e)
    1151         {
    1152             Console.WriteLine(
    1153                 $"{nameof(ConnMultiplexer_HashSlotMoved)}: {nameof(e.OldEndPoint)}-{e.OldEndPoint} To {nameof(e.NewEndPoint)}-{e.NewEndPoint}, ");
    1154         }
    1155 
    1156         /// <summary>
    1157         /// 配置更改时
    1158         /// </summary>
    1159         /// <param name="sender"></param>
    1160         /// <param name="e"></param>
    1161         private static void ConnMultiplexer_ConfigurationChanged(object sender, EndPointEventArgs e)
    1162         {
    1163             Console.WriteLine($"{nameof(ConnMultiplexer_ConfigurationChanged)}: {e.EndPoint}");
    1164         }
    1165 
    1166         /// <summary>
    1167         /// 发生错误时
    1168         /// </summary>
    1169         /// <param name="sender"></param>
    1170         /// <param name="e"></param>
    1171         private static void ConnMultiplexer_ErrorMessage(object sender, RedisErrorEventArgs e)
    1172         {
    1173             Console.WriteLine($"{nameof(ConnMultiplexer_ErrorMessage)}: {e.Message}");
    1174         }
    1175 
    1176         /// <summary>
    1177         /// 物理连接失败时
    1178         /// </summary>
    1179         /// <param name="sender"></param>
    1180         /// <param name="e"></param>
    1181         private static void ConnMultiplexer_ConnectionFailed(object sender, ConnectionFailedEventArgs e)
    1182         {
    1183             Console.WriteLine($"{nameof(ConnMultiplexer_ConnectionFailed)}: {e.Exception}");
    1184         }
    1185 
    1186         /// <summary>
    1187         /// 建立物理连接时
    1188         /// </summary>
    1189         /// <param name="sender"></param>
    1190         /// <param name="e"></param>
    1191         private static void ConnMultiplexer_ConnectionRestored(object sender, ConnectionFailedEventArgs e)
    1192         {
    1193             Console.WriteLine($"{nameof(ConnMultiplexer_ConnectionRestored)}: {e.Exception}");
    1194         }
    1195 
    1196         #endregion 注册事件
    1197 
    1198         /// <summary>
    1199         /// 序列化
    1200         /// </summary>
    1201         /// <param name="obj"></param>
    1202         /// <returns></returns>
    1203         private static byte[] Serialize(object obj)
    1204         {
    1205             if (obj == null)
    1206                 return null;
    1207 
    1208             var binaryFormatter = new BinaryFormatter();
    1209             using (var memoryStream = new MemoryStream())
    1210             {
    1211                 binaryFormatter.Serialize(memoryStream, obj);
    1212                 var data = memoryStream.ToArray();
    1213                 return data;
    1214             }
    1215         }
    1216 
    1217         /// <summary>
    1218         /// 反序列化
    1219         /// </summary>
    1220         /// <typeparam name="T"></typeparam>
    1221         /// <param name="data"></param>
    1222         /// <returns></returns>
    1223         private static T Deserialize<T>(byte[] data)
    1224         {
    1225             if (data == null)
    1226                 return default(T);
    1227 
    1228             var binaryFormatter = new BinaryFormatter();
    1229             using (var memoryStream = new MemoryStream(data))
    1230             {
    1231                 var result = (T)binaryFormatter.Deserialize(memoryStream);
    1232                 return result;
    1233             }
    1234         }
    1235 
    1236         #endregion private method
    1237 
    1238     }
    1239 }
    View Code

     以上代码未全部测试,如若使用请自行验证。如代码有误请帮忙指出,谢谢!

  • 相关阅读:
    IDEA——使用JavaScript Debugger调试代码
    CSS——通过CSS实现展示更多选项和收起
    Antd——表单使用自定义正则进行校验
    GitHub——如何切换默认分支
    Taro——安装和使用
    webpack——You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file.
    SSH——ssh: rejected: administratively prohibited (open failed)
    VUE——三元表达式动态渲染样式
    Windows——80端口被系统占用
    NPM——BASIC realm="Sonatype Nexus
  • 原文地址:https://www.cnblogs.com/hua66/p/9600085.html
Copyright © 2011-2022 走看看