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

 

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

 

posted @ 2018-09-06 18:05  Kaden  阅读(7809)  评论(0编辑  收藏  举报