Redis分布式队列和缓存更新
原文链接:
在使用redis中,我们可能会遇到以下场景:
例如:
某用户向服务器中发送一个请求,服务器将用户请求加入redis任务队列,任务完成则移出队列。
以上场景有几点疑问:
- redis队列中数据如果不仅仅来自于我们的应用程序,那么我们怎么把这个数据加入redis?
- 当redis队列中用户的请求达程序所能处理的峰值。那么我们该如何处理这些用户请求?
解决方案:
- 对外提供接口,将请求数据添加至db。启动一个定时服务,在规定时间扫描db中的请求数据并添加至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 }
以上的代码中是基于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);
上述实例中的 “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 }
上面的 “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 }
可以看到上面代码执行的时间节点与我们所添加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 }
上面我启动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 }
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 }
相关文章:
-
-
父类的静态成员初始化>父类的静态代码块>子类的静态成员初始化>子类的静态代码块>父类的代码块>父类的构造方法>子... [阅读全文]
-
“一字之差”农资商标比比皆是! 是巧合?还是傍大牌? 打开国家工商行政管... [阅读全文]
-
原文链接:https://www.cnblogs.com/hua66/p/9600085.html 在使用Redis中,我们可能会遇到以下场景: 例... [阅读全文]
-
1 public class Test { 2 3 public static void main(String[] args) { 4 //获取当... [阅读全文]
-
现在暴力的引流方法已经过去,优质的内容成为引流的必需品。在优质的文末放上诱饵引导私信是现在主流的玩法。 [阅读全文]
-
版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。
推荐阅读
-
Swoole和Redis实现的并发队列处理系统
-
[原创]分布式系统之缓存的微观应用经验谈(二) 【主从和主备高可用篇】
-
JAVAEE——宜立方商城06:Redis安装、数据类型和持久化方案、Redis集群分析与搭建、实现缓存和同步
-
SpringCloud+Eureka+Feign+Ribbon的简化搭建流程,加入熔断,网关和Redis缓存[2]
-
【转载】在AspNetCore 中 使用Redis实现分布式缓存
-
使用Redis和Java进行数据库缓存
-
Redis之缓存雪崩、缓存穿透、缓存预热、缓存更新、缓存降级
-
memcache和redis缓存对比及我为什么选择redis
-
.net core Redis分布式缓存客户端实现逻辑分析及示例demo
-
Redis全方位详解--数据类型使用场景和redis分布式锁的正确姿势
发表评论