原文链接:https://www.cnblogs.com/hua66/p/9600085.html
在使用Redis中,我们可能会遇到以下场景:
例如:
某用户向服务器中发送一个请求,服务器将用户请求加入Redis任务队列,任务完成则移出队列。
以上场景有几点疑问:
- Redis队列中数据如果不仅仅来自于我们的应用程序,那么我们怎么把这个数据加入Redis?
- 当Redis队列中用户的请求达程序所能处理的峰值。那么我们该如何处理这些用户请求?
解决方案:
- 对外提供接口,将请求数据添加至DB。启动一个定时服务,在规定时间扫描DB中的请求数据并添加至Redis队列。
- 使用分布式异步队列。
以上解决方案都可以使用插件来实现。
一、
关于Quartz.Net可以通过上面链接获取官方API。它与SQL Server中的代理作业有着同样功能。
代码示例:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
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 }
以上的代码中是基于Quartz封装一个添加了Job的方法。这个方法依赖于 “IJobDetail” 和 “ITrigger” 这两个对象。
“IJobDetail” 表示Job的身份信息,“ITrigger” 则包含了Job执行信息,它表示Job该如何执行。
以下为调用示例:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 QuartzHelper quartzHelper = QuartzHelper.CreateInstance(); 2 quartzHelper.AddJob<TestJob>("testJob", "testJob_Group",false, "testJob_Trigger",1*10);
上述实例中的 “TestJob” 实现Quartz.Net中的 "IJob" 接口。这个接口只有一个方法 “Execute”,并由Quartz.Net框架自行调用该方法。
你可以在此方法中执行你的代码。并在添加该Job制定你的执行策略 “ITrigger” 对象。然后框架会根据你制定的策略进行调用。调用参数请参见上述封装。
下面是向Redis队列插入数据的示例Job:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
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 }
上面的 “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:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
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 }
可以看到上面代码执行的时间节点与我们所添加job中的 ”ITrigger “ 的触发策略完全一致。至此,我们第一步已得到验证。
2.启动处理Redis队列中请求的程序。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
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 }
上面我启动3个客户端实例,他们一起处理Redis队列中的请求。每当Job向Redis队列中添加请求对象后就会立即被我们处理请求的程序获取并消费,每当一个请求被消费就会被移出Redis队列。并且遵循先入先出的准则。按照上述,如果出现主程序请求量过高情形,我们只需要启动多个处理请求的辅助程序即可缓解主程序的压力。
至此上面的两个问题已得到验证。
如下附个人基于 "Quartz.Net" 和 "StackExchange.Redis" 封装的帮助类
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
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 }
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
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 }
以上代码未全部测试,如若使用请自行验证。如代码有误请帮忙指出,谢谢!