Redis 小白指南(一)- 简介、安装、GUI 和 C# 驱动介绍
Redis 小白指南(一)- 简介、安装、GUI 和 C# 驱动介绍
目录
- 简介
- 安装
- 入门指令
- GUI 工具
- C# 驱动介绍
简介
ANSI C 编写,开源,基于内存,可持久化,一个键值对的数据库,用法简单。
支持的类型:字符串、散列、列表、集合和有序集合。
因为 Redis 默认将所有数据都存储到内存中,并且内存的读写速度远远高于硬盘,因此,比其他基于硬盘存储的数据库在性能上体现的优势非常明显。不过这样也引发了一个数据安全性的问题,程序异常或退出后数据会出现丢失的情形,现在新的版本已经提供了数据持久化(RDB + AOF)的支持,即可以将内存中的数据异步写入到硬盘上,同时不会影响其它功能的运行。
redis 可以为每个键设置生存时间,到期自动删除,也就是说可以作为缓存系统(这也是企业主要的运用场景)进行使用。
相对于 Memcached,简单的说:Redis 单线程模型,Memcached 支持多线程,但 Redis 支持的功能和数据类型更多,更简单易用,并且 redis 的性能在绝大部分场合下都不会成为系统瓶颈,不过在多核服务器上使用的情况下,理论上 Memcached 比 redis 性能更高。所以,在新项目中,建议使用 redis 代替 Memcached。
Redis 还可以限定数据占用的最大内存空间,在数据达到空间限制后按一定规则自动淘汰不需要的键;也支持构建高性能的队列(不过很多企业会选择第三方的 MQ,如:RabbitMQ)。
安装
它的约定次版本号(即第一个小数点后的数字)为偶数的版本是稳定版(如 v2.8,v3.0)。
为了减少学习成本,我们直接使用 windows 版本的就可以,想学习 Linux 部署的,先搜搜别人的文章吧。
redis-windows-3.0(搜索了一下,最新的正式版是 3.2):下载地址
文件简单说明:
入门指令
1.启动 CMD:
$ redis-server $ redis-server --port 6380 //自定义端口
2.停止:
$ redis-cli SHUTDOWN
3.PING 命令:
测试与 redis 的连接是否正常,正常返回 PONG
$ redis-cli PING
GUI 工具
Redis Client:一个基于Java SWT 和 Jedis 编写的 redis 客户端 GUI 工具。可从 https://github.com/caoxinyu/RedisClient 下载。
从图可知,redis 包含了 16 个数据库。上面的每个数据库默认从 0 开始的递增数字命名。
因为该程序打包后的压缩包 >10 M,无法上传到 cnblogs,如有需要的童鞋请加群在群文件中下载压缩包。
补充一下园友(心态要好)推荐的其它 GUI 工具 RedisDeskTopManager:https://redisdesktop.com/download。
C# 驱动
之前在 《使用 StackExchange.Redis 封装属于自己的 RedisHelper》 曾经发布了一篇使用 StackExchange.Redis 进行了简单封装的 RedisHelper,你可以选择查看之前的文章,从中借鉴一些思想或者给出一些建议。
这里是更新后的 Helper 代码(直接展开即可),代码的后续更新在 GitHub 上。
1 #region 2 3 using System; 4 using System.Collections.Generic; 5 using System.Configuration; 6 using System.IO; 7 using System.Linq; 8 using System.Runtime.Serialization.Formatters.Binary; 9 using System.Threading.Tasks; 10 using StackExchange.Redis; 11 12 #endregion 13 14 namespace Wen.Helpers.Common.Redis 15 { 16 /// <summary> 17 /// Redis 助手 18 /// </summary> 19 public class RedisHelper 20 { 21 /// <summary> 22 /// 获取 Redis 连接对象 23 /// </summary> 24 /// <returns></returns> 25 public IConnectionMultiplexer GetConnectionRedisMultiplexer() 26 { 27 if (_connMultiplexer == null || !_connMultiplexer.IsConnected) 28 lock (Locker) 29 { 30 if (_connMultiplexer == null || !_connMultiplexer.IsConnected) 31 _connMultiplexer = ConnectionMultiplexer.Connect(ConnectionString); 32 } 33 34 return _connMultiplexer; 35 } 36 37 #region 其它 38 39 public ITransaction GetTransaction() 40 { 41 return _db.CreateTransaction(); 42 } 43 44 #endregion 其它 45 46 #region private field 47 48 /// <summary> 49 /// 连接字符串 50 /// </summary> 51 private static readonly string ConnectionString; 52 53 /// <summary> 54 /// redis 连接对象 55 /// </summary> 56 private static IConnectionMultiplexer _connMultiplexer; 57 58 /// <summary> 59 /// 默认的 Key 值(用来当作 RedisKey 的前缀) 60 /// </summary> 61 private static readonly string DefaultKey; 62 63 /// <summary> 64 /// 锁 65 /// </summary> 66 private static readonly object Locker = new object(); 67 68 /// <summary> 69 /// 数据库 70 /// </summary> 71 private readonly IDatabase _db; 72 73 #endregion private field 74 75 #region 构造函数 76 77 static RedisHelper() 78 { 79 ConnectionString = ConfigurationManager.ConnectionStrings["RedisConnectionString"].ConnectionString; 80 _connMultiplexer = ConnectionMultiplexer.Connect(ConnectionString); 81 DefaultKey = ConfigurationManager.AppSettings["Redis.DefaultKey"]; 82 AddRegisterEvent(); 83 } 84 85 public RedisHelper(int db = 0) 86 { 87 _db = _connMultiplexer.GetDatabase(db); 88 } 89 90 #endregion 构造函数 91 92 #region String 操作 93 94 /// <summary> 95 /// 设置 key 并保存字符串(如果 key 已存在,则覆盖值) 96 /// </summary> 97 /// <param name="key"></param> 98 /// <param name="value"></param> 99 /// <param name="expiry"></param> 100 /// <returns></returns> 101 public bool StringSet(string key, string value, TimeSpan? expiry = null) 102 { 103 key = AddKeyPrefix(key); 104 return _db.StringSet(key, value, expiry); 105 } 106 107 /// <summary> 108 /// 保存多个 Key-value 109 /// </summary> 110 /// <param name="keyValuePairs"></param> 111 /// <returns></returns> 112 public bool StringSet(IEnumerable<KeyValuePair<string, string>> keyValuePairs) 113 { 114 var pairs = keyValuePairs.Select(x => new KeyValuePair<RedisKey, RedisValue>(AddKeyPrefix(x.Key), x.Value)); 115 return _db.StringSet(pairs.ToArray()); 116 } 117 118 /// <summary> 119 /// 获取字符串 120 /// </summary> 121 /// <param name="redisKey"></param> 122 /// <param name="expiry"></param> 123 /// <returns></returns> 124 public string StringGet(string redisKey) 125 { 126 redisKey = AddKeyPrefix(redisKey); 127 return _db.StringGet(redisKey); 128 } 129 130 /// <summary> 131 /// 存储一个对象(该对象会被序列化保存) 132 /// </summary> 133 /// <param name="key"></param> 134 /// <param name="value"></param> 135 /// <param name="expiry"></param> 136 /// <returns></returns> 137 public bool StringSet<T>(string key, T value, TimeSpan? expiry = null) 138 { 139 key = AddKeyPrefix(key); 140 var json = Serialize(value); 141 142 return _db.StringSet(key, json, expiry); 143 } 144 145 /// <summary> 146 /// 获取一个对象(会进行反序列化) 147 /// </summary> 148 /// <param name="key"></param> 149 /// <param name="expiry"></param> 150 /// <returns></returns> 151 public T StringGet<T>(string key, TimeSpan? expiry = null) 152 { 153 key = AddKeyPrefix(key); 154 return Deserialize<T>(_db.StringGet(key)); 155 } 156 157 /// <summary> 158 /// 在指定 key 处实现增量的递增,如果该键不存在,则在执行前将其设置为 0 159 /// </summary> 160 /// <param name="key"></param> 161 /// <param name="value"></param> 162 /// <returns></returns> 163 public double StringIncrement(string key, double value = 1) 164 { 165 key = AddKeyPrefix(key); 166 return _db.StringIncrement(key, value); 167 } 168 169 /// <summary> 170 /// 在指定 key 处实现增量的递减,如果该键不存在,则在执行前将其设置为 0 171 /// </summary> 172 /// <param name="key"></param> 173 /// <param name="value"></param> 174 /// <returns></returns> 175 public double StringDecrement(string key, double value = 1) 176 { 177 key = AddKeyPrefix(key); 178 return _db.StringDecrement(key, value); 179 } 180 181 #region async 182 183 /// <summary> 184 /// 保存一个字符串值 185 /// </summary> 186 /// <param name="key"></param> 187 /// <param name="value"></param> 188 /// <param name="expiry"></param> 189 /// <returns></returns> 190 public async Task<bool> StringSetAsync(string key, string value, TimeSpan? expiry = null) 191 { 192 key = AddKeyPrefix(key); 193 return await _db.StringSetAsync(key, value, expiry); 194 } 195 196 /// <summary> 197 /// 保存一组字符串值 198 /// </summary> 199 /// <param name="keyValuePairs"></param> 200 /// <returns></returns> 201 public async Task<bool> StringSetAsync(IEnumerable<KeyValuePair<string, string>> keyValuePairs) 202 { 203 var pairs = keyValuePairs.Select(x => new KeyValuePair<RedisKey, RedisValue>(AddKeyPrefix(x.Key), x.Value)); 204 return await _db.StringSetAsync(pairs.ToArray()); 205 } 206 207 /// <summary> 208 /// 获取单个值 209 /// </summary> 210 /// <param name="key"></param> 211 /// <param name="value"></param> 212 /// <param name="expiry"></param> 213 /// <returns></returns> 214 public async Task<string> StringGetAsync(string key, string value, TimeSpan? expiry = null) 215 { 216 key = AddKeyPrefix(key); 217 return await _db.StringGetAsync(key); 218 } 219 220 /// <summary> 221 /// 存储一个对象(该对象会被序列化保存) 222 /// </summary> 223 /// <param name="key"></param> 224 /// <param name="value"></param> 225 /// <param name="expiry"></param> 226 /// <returns></returns> 227 public async Task<bool> StringSetAsync<T>(string key, T value, TimeSpan? expiry = null) 228 { 229 key = AddKeyPrefix(key); 230 var json = Serialize(value); 231 return await _db.StringSetAsync(key, json, expiry); 232 } 233 234 /// <summary> 235 /// 获取一个对象(会进行反序列化) 236 /// </summary> 237 /// <param name="key"></param> 238 /// <param name="expiry"></param> 239 /// <returns></returns> 240 public async Task<T> StringGetAsync<T>(string key, TimeSpan? expiry = null) 241 { 242 key = AddKeyPrefix(key); 243 return Deserialize<T>(await _db.StringGetAsync(key)); 244 } 245 246 /// <summary> 247 /// 在指定 key 处实现增量的递增,如果该键不存在,则在执行前将其设置为 0 248 /// </summary> 249 /// <param name="key"></param> 250 /// <param name="value"></param> 251 /// <returns></returns> 252 public async Task<double> StringIncrementAsync(string key, double value = 1) 253 { 254 key = AddKeyPrefix(key); 255 return await _db.StringIncrementAsync(key, value); 256 } 257 258 /// <summary> 259 /// 在指定 key 处实现增量的递减,如果该键不存在,则在执行前将其设置为 0 260 /// </summary> 261 /// <param name="key"></param> 262 /// <param name="value"></param> 263 /// <returns></returns> 264 public async Task<double> StringDecrementAsync(string key, double value = 1) 265 { 266 key = AddKeyPrefix(key); 267 return await _db.StringDecrementAsync(key, value); 268 } 269 270 #endregion async 271 272 #endregion String 操作 273 274 #region Hash 操作 275 276 /// <summary> 277 /// 判断该字段是否存在 hash 中 278 /// </summary> 279 /// <param name="key"></param> 280 /// <param name="hashField"></param> 281 /// <returns></returns> 282 public bool HashExists(string key, string hashField) 283 { 284 key = AddKeyPrefix(key); 285 return _db.HashExists(key, hashField); 286 } 287 288 /// <summary> 289 /// 从 hash 中移除指定字段 290 /// </summary> 291 /// <param name="key"></param> 292 /// <param name="hashField"></param> 293 /// <returns></returns> 294 public bool HashDelete(string key, string hashField) 295 { 296 key = AddKeyPrefix(key); 297 return _db.HashDelete(key, hashField); 298 } 299 300 /// <summary> 301 /// 从 hash 中移除指定字段 302 /// </summary> 303 /// <param name="key"></param> 304 /// <param name="hashFields"></param> 305 /// <returns></returns> 306 public long HashDelete(string key, IEnumerable<string> hashFields) 307 { 308 key = AddKeyPrefix(key); 309 var fields = hashFields.Select(x => (RedisValue) x); 310 311 return _db.HashDelete(key, fields.ToArray()); 312 } 313 314 /// <summary> 315 /// 在 hash 设定值 316 /// </summary> 317 /// <param name="key"></param> 318 /// <param name="hashField"></param> 319 /// <param name="value"></param> 320 /// <returns></returns> 321 public bool HashSet(string key, string hashField, string value) 322 { 323 key = AddKeyPrefix(key); 324 return _db.HashSet(key, hashField, value); 325 } 326 327 /// <summary> 328 /// 在 hash 中设定值 329 /// </summary> 330 /// <param name="key"></param> 331 /// <param name="hashFields"></param> 332 public void HashSet(string key, IEnumerable<KeyValuePair<string, string>> hashFields) 333 { 334 key = AddKeyPrefix(key); 335 var entries = hashFields.Select(x => new HashEntry(x.Key, x.Value)); 336 337 _db.HashSet(key, entries.ToArray()); 338 } 339 340 /// <summary> 341 /// 在 hash 中获取值 342 /// </summary> 343 /// <param name="key"></param> 344 /// <param name="hashField"></param> 345 /// <returns></returns> 346 public string HashGet(string key, string hashField) 347 { 348 key = AddKeyPrefix(key); 349 return _db.HashGet(key, hashField); 350 } 351 352 /// <summary> 353 /// 在 hash 中获取值 354 /// </summary> 355 /// <param name="key"></param> 356 /// <param name="hashFields"></param> 357 /// <returns></returns> 358 public IEnumerable<string> HashGet(string key, IEnumerable<string> hashFields) 359 { 360 key = AddKeyPrefix(key); 361 var fields = hashFields.Select(x => (RedisValue) x); 362 363 return ConvertStrings(_db.HashGet(key, fields.ToArray())); 364 } 365 366 /// <summary> 367 /// 从 hash 返回所有的字段值 368 /// </summary> 369 /// <param name="key"></param> 370 /// <returns></returns> 371 public IEnumerable<string> HashKeys(string key) 372 { 373 key = AddKeyPrefix(key); 374 return ConvertStrings(_db.HashKeys(key)); 375 } 376 377 /// <summary> 378 /// 返回 hash 中的所有值 379 /// </summary> 380 /// <param name="key"></param> 381 /// <returns></returns> 382 public IEnumerable<string> HashValues(string key) 383 { 384 key = AddKeyPrefix(key); 385 return ConvertStrings(_db.HashValues(key)); 386 } 387 388 /// <summary> 389 /// 在 hash 设定值(序列化) 390 /// </summary> 391 /// <param name="key"></param> 392 /// <param name="hashField"></param> 393 /// <param name="redisValue"></param> 394 /// <returns></returns> 395 public bool HashSet<T>(string key, string hashField, T redisValue) 396 { 397 key = AddKeyPrefix(key); 398 var json = Serialize(redisValue); 399 400 return _db.HashSet(key, hashField, json); 401 } 402 403 /// <summary> 404 /// 在 hash 中获取值(反序列化) 405 /// </summary> 406 /// <param name="key"></param> 407 /// <param name="hashField"></param> 408 /// <returns></returns> 409 public T HashGet<T>(string key, string hashField) 410 { 411 key = AddKeyPrefix(key); 412 return Deserialize<T>(_db.HashGet(key, hashField)); 413 } 414 415 /// <summary> 416 /// 指定键递增 417 /// </summary> 418 /// <param name="key"></param> 419 /// <param name="hashField"></param> 420 /// <param name="value"></param> 421 /// <returns></returns> 422 public double HashIncrement(string key, string hashField, double value = 1) 423 { 424 key = AddKeyPrefix(key); 425 return _db.HashIncrement(key, hashField, value); 426 } 427 428 /// <summary> 429 /// 指定键递减 430 /// </summary> 431 /// <param name="key"></param> 432 /// <param name="hashField"></param> 433 /// <param name="value"></param> 434 /// <returns></returns> 435 public double HashDecrement(string key, string hashField, double value = 1) 436 { 437 key = AddKeyPrefix(key); 438 return _db.HashDecrement(key, hashField, value); 439 } 440 441 #region async 442 443 /// <summary> 444 /// 判断该字段是否存在 hash 中 445 /// </summary> 446 /// <param name="redisKey"></param> 447 /// <param name="hashField"></param> 448 /// <returns></returns> 449 public async Task<bool> HashExistsAsync(string redisKey, string hashField) 450 { 451 redisKey = AddKeyPrefix(redisKey); 452 return await _db.HashExistsAsync(redisKey, hashField); 453 } 454 455 /// <summary> 456 /// 从 hash 中移除指定字段 457 /// </summary> 458 /// <param name="redisKey"></param> 459 /// <param name="hashField"></param> 460 /// <returns></returns> 461 public async Task<bool> HashDeleteAsync(string redisKey, string hashField) 462 { 463 redisKey = AddKeyPrefix(redisKey); 464 return await _db.HashDeleteAsync(redisKey, hashField); 465 } 466 467 /// <summary> 468 /// 从 hash 中移除指定字段 469 /// </summary> 470 /// <param name="redisKey"></param> 471 /// <param name="hashFields"></param> 472 /// <returns></returns> 473 public async Task<long> HashDeleteAsync(string redisKey, IEnumerable<string> hashFields) 474 { 475 redisKey = AddKeyPrefix(redisKey); 476 var fields = hashFields.Select(x => (RedisValue) x); 477 478 return await _db.HashDeleteAsync(redisKey, fields.ToArray()); 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(string redisKey, string hashField, string value) 489 { 490 redisKey = AddKeyPrefix(redisKey); 491 return await _db.HashSetAsync(redisKey, hashField, value); 492 } 493 494 /// <summary> 495 /// 在 hash 中设定值 496 /// </summary> 497 /// <param name="redisKey"></param> 498 /// <param name="hashFields"></param> 499 public async Task HashSetAsync(string redisKey, IEnumerable<KeyValuePair<string, string>> hashFields) 500 { 501 redisKey = AddKeyPrefix(redisKey); 502 var entries = hashFields.Select(x => new HashEntry(AddKeyPrefix(x.Key), x.Value)); 503 await _db.HashSetAsync(redisKey, entries.ToArray()); 504 } 505 506 /// <summary> 507 /// 在 hash 中获取值 508 /// </summary> 509 /// <param name="redisKey"></param> 510 /// <param name="hashField"></param> 511 /// <returns></returns> 512 public async Task<string> HashGetAsync(string redisKey, string hashField) 513 { 514 redisKey = AddKeyPrefix(redisKey); 515 return await _db.HashGetAsync(redisKey, hashField); 516 } 517 518 /// <summary> 519 /// 在 hash 中获取值 520 /// </summary> 521 /// <param name="redisKey"></param> 522 /// <param name="hashFields"></param> 523 /// <param name="value"></param> 524 /// <returns></returns> 525 public async Task<IEnumerable<string>> HashGetAsync(string redisKey, IEnumerable<string> hashFields, 526 string value) 527 { 528 redisKey = AddKeyPrefix(redisKey); 529 var fields = hashFields.Select(x => (RedisValue) x); 530 531 return ConvertStrings(await _db.HashGetAsync(redisKey, fields.ToArray())); 532 } 533 534 /// <summary> 535 /// 从 hash 返回所有的字段值 536 /// </summary> 537 /// <param name="redisKey"></param> 538 /// <returns></returns> 539 public async Task<IEnumerable<string>> HashKeysAsync(string redisKey) 540 { 541 redisKey = AddKeyPrefix(redisKey); 542 return ConvertStrings(await _db.HashKeysAsync(redisKey)); 543 } 544 545 /// <summary> 546 /// 返回 hash 中的所有值 547 /// </summary> 548 /// <param name="redisKey"></param> 549 /// <returns></returns> 550 public async Task<IEnumerable<string>> HashValuesAsync(string redisKey) 551 { 552 redisKey = AddKeyPrefix(redisKey); 553 return ConvertStrings(await _db.HashValuesAsync(redisKey)); 554 } 555 556 /// <summary> 557 /// 在 hash 设定值(序列化) 558 /// </summary> 559 /// <param name="redisKey"></param> 560 /// <param name="hashField"></param> 561 /// <param name="value"></param> 562 /// <returns></returns> 563 public async Task<bool> HashSetAsync<T>(string redisKey, string hashField, T value) 564 { 565 redisKey = AddKeyPrefix(redisKey); 566 var json = Serialize(value); 567 return await _db.HashSetAsync(redisKey, hashField, json); 568 } 569 570 /// <summary> 571 /// 在 hash 中获取值(反序列化) 572 /// </summary> 573 /// <param name="redisKey"></param> 574 /// <param name="hashField"></param> 575 /// <returns></returns> 576 public async Task<T> HashGetAsync<T>(string redisKey, string hashField) 577 { 578 redisKey = AddKeyPrefix(redisKey); 579 return Deserialize<T>(await _db.HashGetAsync(redisKey, hashField)); 580 } 581 582 /// <summary> 583 /// 指定键递增 584 /// </summary> 585 /// <param name="key"></param> 586 /// <param name="hashField"></param> 587 /// <param name="value"></param> 588 /// <returns></returns> 589 public async Task<double> HashIncrementAsync(string key, string hashField, double value = 1) 590 { 591 key = AddKeyPrefix(key); 592 return await _db.HashIncrementAsync(key, hashField, value); 593 } 594 595 /// <summary> 596 /// 指定键递减 597 /// </summary> 598 /// <param name="key"></param> 599 /// <param name="hashField"></param> 600 /// <param name="value"></param> 601 /// <returns></returns> 602 public async Task<double> HashDecrementAsync(string key, string hashField, double value = 1) 603 { 604 key = AddKeyPrefix(key); 605 return await _db.HashDecrementAsync(key, hashField, value); 606 } 607 608 #endregion async 609 610 #endregion Hash 操作 611 612 #region List 操作 613 614 /// <summary> 615 /// 移除并返回存储在该键列表的第一个元素 616 /// </summary> 617 /// <param name="key"></param> 618 /// <returns></returns> 619 public string ListLeftPop(string key) 620 { 621 key = AddKeyPrefix(key); 622 return _db.ListLeftPop(key); 623 } 624 625 /// <summary> 626 /// 出列,移除并返回存储在该键列表的最后一个元素 627 /// </summary> 628 /// <param name="key"></param> 629 /// <returns></returns> 630 public string ListRightPop(string key) 631 { 632 key = AddKeyPrefix(key); 633 return _db.ListRightPop(key); 634 } 635 636 /// <summary> 637 /// 移除列表指定键上与该值相同的元素 638 /// </summary> 639 /// <param name="key"></param> 640 /// <param name="value"></param> 641 /// <returns></returns> 642 public long ListRemove(string key, string value) 643 { 644 key = AddKeyPrefix(key); 645 return _db.ListRemove(key, value); 646 } 647 648 /// <summary> 649 /// 入列,在列表尾部插入值。如果键不存在,先创建再插入值 650 /// </summary> 651 /// <param name="key"></param> 652 /// <param name="value"></param> 653 /// <returns></returns> 654 public long ListRightPush(string key, string value) 655 { 656 key = AddKeyPrefix(key); 657 return _db.ListRightPush(key, value); 658 } 659 660 /// <summary> 661 /// 在列表头部插入值。如果键不存在,先创建再插入值 662 /// </summary> 663 /// <param name="key"></param> 664 /// <param name="value"></param> 665 /// <returns></returns> 666 public long ListLeftPush(string key, string value) 667 { 668 key = AddKeyPrefix(key); 669 return _db.ListLeftPush(key, value); 670 } 671 672 /// <summary> 673 /// 返回列表上该键的长度,如果不存在,返回 0 674 /// </summary> 675 /// <param name="key"></param> 676 /// <returns></returns> 677 public long ListLength(string key) 678 { 679 key = AddKeyPrefix(key); 680 return _db.ListLength(key); 681 } 682 683 /// <summary> 684 /// 返回在该列表上键所对应的元素 685 /// </summary> 686 /// <param name="key"></param> 687 /// <param name="start"></param> 688 /// <param name="stop"></param> 689 /// <returns></returns> 690 public IEnumerable<string> ListRange(string key, long start = 0L, long stop = -1L) 691 { 692 key = AddKeyPrefix(key); 693 return ConvertStrings(_db.ListRange(key, start, stop)); 694 } 695 696 /// <summary> 697 /// 移除并返回存储在该键列表的第一个元素 698 /// </summary> 699 /// <param name="key"></param> 700 /// <returns></returns> 701 public T ListLeftPop<T>(string key) 702 { 703 key = AddKeyPrefix(key); 704 return Deserialize<T>(_db.ListLeftPop(key)); 705 } 706 707 /// <summary> 708 /// 出队,移除并返回存储在该键列表的最后一个元素 709 /// </summary> 710 /// <param name="key"></param> 711 /// <returns></returns> 712 public T ListRightPop<T>(string key) 713 { 714 key = AddKeyPrefix(key); 715 return Deserialize<T>(_db.ListRightPop(key)); 716 } 717 718 /// <summary> 719 /// 入队,在列表尾部插入值。如果键不存在,先创建再插入值 720 /// </summary> 721 /// <param name="key"></param> 722 /// <param name="value"></param> 723 /// <returns></returns> 724 public long ListRightPush<T>(string key, T value) 725 { 726 key = AddKeyPrefix(key); 727 return _db.ListRightPush(key, Serialize(value)); 728 } 729 730 /// <summary> 731 /// 在列表头部插入值。如果键不存在,先创建再插入值 732 /// </summary> 733 /// <param name="key"></param> 734 /// <param name="value"></param> 735 /// <returns></returns> 736 public long ListLeftPush<T>(string key, T value) 737 { 738 key = AddKeyPrefix(key); 739 return _db.ListLeftPush(key, Serialize(value)); 740 } 741 742 #region List-async 743 744 /// <summary> 745 /// 移除并返回存储在该键列表的第一个元素 746 /// </summary> 747 /// <param name="key"></param> 748 /// <returns></returns> 749 public async Task<string> ListLeftPopAsync(string key) 750 { 751 key = AddKeyPrefix(key); 752 return await _db.ListLeftPopAsync(key); 753 } 754 755 /// <summary> 756 /// 移除并返回存储在该键列表的最后一个元素 757 /// </summary> 758 /// <param name="key"></param> 759 /// <returns></returns> 760 public async Task<string> ListRightPopAsync(string key) 761 { 762 key = AddKeyPrefix(key); 763 return await _db.ListRightPopAsync(key); 764 } 765 766 /// <summary> 767 /// 移除列表指定键上与该值相同的元素 768 /// </summary> 769 /// <param name="key"></param> 770 /// <param name="value"></param> 771 /// <returns></returns> 772 public async Task<long> ListRemoveAsync(string key, string value) 773 { 774 key = AddKeyPrefix(key); 775 return await _db.ListRemoveAsync(key, value); 776 } 777 778 /// <summary> 779 /// 在列表尾部插入值。如果键不存在,先创建再插入值 780 /// </summary> 781 /// <param name="key"></param> 782 /// <param name="value"></param> 783 /// <returns></returns> 784 public async Task<long> ListRightPushAsync(string key, string value) 785 { 786 key = AddKeyPrefix(key); 787 return await _db.ListRightPushAsync(key, value); 788 } 789 790 /// <summary> 791 /// 在列表头部插入值。如果键不存在,先创建再插入值 792 /// </summary> 793 /// <param name="key"></param> 794 /// <param name="value"></param> 795 /// <returns></returns> 796 public async Task<long> ListLeftPushAsync(string key, string value) 797 { 798 key = AddKeyPrefix(key); 799 return await _db.ListLeftPushAsync(key, value); 800 } 801 802 /// <summary> 803 /// 返回列表上该键的长度,如果不存在,返回 0 804 /// </summary> 805 /// <param name="key"></param> 806 /// <returns></returns> 807 public async Task<long> ListLengthAsync(string key) 808 { 809 key = AddKeyPrefix(key); 810 return await _db.ListLengthAsync(key); 811 } 812 813 /// <summary> 814 /// 返回在该列表上键所对应的元素 815 /// </summary> 816 /// <param name="key"></param> 817 /// <param name="start"></param> 818 /// <param name="stop"></param> 819 /// <returns></returns> 820 public async Task<IEnumerable<string>> ListRangeAsync(string key, long start = 0L, long stop = -1L) 821 { 822 key = AddKeyPrefix(key); 823 var query = await _db.ListRangeAsync(key, start, stop); 824 return query.Select(x => x.ToString()); 825 } 826 827 /// <summary> 828 /// 移除并返回存储在该键列表的第一个元素 829 /// </summary> 830 /// <param name="key"></param> 831 /// <returns></returns> 832 public async Task<T> ListLeftPopAsync<T>(string key) 833 { 834 key = AddKeyPrefix(key); 835 return Deserialize<T>(await _db.ListLeftPopAsync(key)); 836 } 837 838 /// <summary> 839 /// 移除并返回存储在该键列表的最后一个元素 840 /// </summary> 841 /// <param name="key"></param> 842 /// <returns></returns> 843 public async Task<T> ListRightPopAsync<T>(string key) 844 { 845 key = AddKeyPrefix(key); 846 return Deserialize<T>(await _db.ListRightPopAsync(key)); 847 } 848 849 /// <summary> 850 /// 在列表尾部插入值。如果键不存在,先创建再插入值 851 /// </summary> 852 /// <param name="key"></param> 853 /// <param name="value"></param> 854 /// <returns></returns> 855 public async Task<long> ListRightPushAsync<T>(string key, T value) 856 { 857 key = AddKeyPrefix(key); 858 return await _db.ListRightPushAsync(key, Serialize(value)); 859 } 860 861 /// <summary> 862 /// 在列表头部插入值。如果键不存在,先创建再插入值 863 /// </summary> 864 /// <param name="key"></param> 865 /// <param name="value"></param> 866 /// <returns></returns> 867 public async Task<long> ListLeftPushAsync<T>(string key, T value) 868 { 869 key = AddKeyPrefix(key); 870 return await _db.ListLeftPushAsync(key, Serialize(value)); 871 } 872 873 #endregion List-async 874 875 #endregion List 操作 876 877 #region SortedSet 操作 878 879 /// <summary> 880 /// SortedSet 新增 881 /// </summary> 882 /// <param name="key"></param> 883 /// <param name="member"></param> 884 /// <param name="score"></param> 885 /// <returns></returns> 886 public bool SortedSetAdd(string key, string member, double score) 887 { 888 key = AddKeyPrefix(key); 889 return _db.SortedSetAdd(key, member, score); 890 } 891 892 /// <summary> 893 /// 在有序集合中返回指定范围的元素,默认情况下从低到高。 894 /// </summary> 895 /// <param name="key"></param> 896 /// <param name="start"></param> 897 /// <param name="stop"></param> 898 /// <param name="order"></param> 899 /// <returns></returns> 900 public IEnumerable<string> SortedSetRangeByRank(string key, long start = 0L, long stop = -1L, 901 OrderType order = OrderType.Ascending) 902 { 903 key = AddKeyPrefix(key); 904 return _db.SortedSetRangeByRank(key, start, stop, (Order) order).Select(x => x.ToString()); 905 } 906 907 /// <summary> 908 /// 返回有序集合的元素个数 909 /// </summary> 910 /// <param name="key"></param> 911 /// <returns></returns> 912 public long SortedSetLength(string key) 913 { 914 key = AddKeyPrefix(key); 915 return _db.SortedSetLength(key); 916 } 917 918 /// <summary> 919 /// 返回有序集合的元素个数 920 /// </summary> 921 /// <param name="key"></param> 922 /// <param name="memebr"></param> 923 /// <returns></returns> 924 public bool SortedSetRemove(string key, string memebr) 925 { 926 key = AddKeyPrefix(key); 927 return _db.SortedSetRemove(key, memebr); 928 } 929 930 /// <summary> 931 /// SortedSet 新增 932 /// </summary> 933 /// <param name="key"></param> 934 /// <param name="member"></param> 935 /// <param name="score"></param> 936 /// <returns></returns> 937 public bool SortedSetAdd<T>(string key, T member, double score) 938 { 939 key = AddKeyPrefix(key); 940 var json = Serialize(member); 941 942 return _db.SortedSetAdd(key, json, score); 943 } 944 945 /// <summary> 946 /// 增量的得分排序的集合中的成员存储键值键按增量 947 /// </summary> 948 /// <param name="key"></param> 949 /// <param name="member"></param> 950 /// <param name="value"></param> 951 /// <returns></returns> 952 public double SortedSetIncrement(string key, string member, double value = 1) 953 { 954 key = AddKeyPrefix(key); 955 return _db.SortedSetIncrement(key, member, value); 956 } 957 958 #region SortedSet-Async 959 960 /// <summary> 961 /// SortedSet 新增 962 /// </summary> 963 /// <param name="key"></param> 964 /// <param name="member"></param> 965 /// <param name="score"></param> 966 /// <returns></returns> 967 public async Task<bool> SortedSetAddAsync(string key, string member, double score) 968 { 969 key = AddKeyPrefix(key); 970 return await _db.SortedSetAddAsync(key, member, score); 971 } 972 973 /// <summary> 974 /// 在有序集合中返回指定范围的元素,默认情况下从低到高。 975 /// </summary> 976 /// <param name="key"></param> 977 /// <returns></returns> 978 public async Task<IEnumerable<string>> SortedSetRangeByRankAsync(string key) 979 { 980 key = AddKeyPrefix(key); 981 return ConvertStrings(await _db.SortedSetRangeByRankAsync(key)); 982 } 983 984 /// <summary> 985 /// 返回有序集合的元素个数 986 /// </summary> 987 /// <param name="key"></param> 988 /// <returns></returns> 989 public async Task<long> SortedSetLengthAsync(string key) 990 { 991 key = AddKeyPrefix(key); 992 return await _db.SortedSetLengthAsync(key); 993 } 994 995 /// <summary> 996 /// 返回有序集合的元素个数 997 /// </summary> 998 /// <param name="key"></param> 999 /// <param name="memebr"></param> 1000 /// <returns></returns> 1001 public async Task<bool> SortedSetRemoveAsync(string key, string memebr) 1002 { 1003 key = AddKeyPrefix(key); 1004 return await _db.SortedSetRemoveAsync(key, memebr); 1005 } 1006 1007 /// <summary> 1008 /// SortedSet 新增 1009 /// </summary> 1010 /// <param name="key"></param> 1011 /// <param name="member"></param> 1012 /// <param name="score"></param> 1013 /// <returns></returns> 1014 public async Task<bool> SortedSetAddAsync<T>(string key, T member, double score) 1015 { 1016 key = AddKeyPrefix(key); 1017 var json = Serialize(member); 1018 1019 return await _db.SortedSetAddAsync(key, json, score); 1020 } 1021 1022 /// <summary> 1023 /// 增量的得分排序的集合中的成员存储键值键按增量 1024 /// </summary> 1025 /// <param name="key"></param> 1026 /// <param name="member"></param> 1027 /// <param name="value"></param> 1028 /// <returns></returns> 1029 public Task<double> SortedSetIncrementAsync(string key, string member, double value = 1) 1030 { 1031 key = AddKeyPrefix(key); 1032 return _db.SortedSetIncrementAsync(key, member, value); 1033 } 1034 1035 #endregion SortedSet-Async 1036 1037 #endregion SortedSet 操作 1038 1039 #region key 操作 1040 1041 /// <summary> 1042 /// 移除指定 Key 1043 /// </summary> 1044 /// <param name="key"></param> 1045 /// <returns></returns> 1046 public bool KeyDelete(string key) 1047 { 1048 key = AddKeyPrefix(key); 1049 return _db.KeyDelete(key); 1050 } 1051 1052 /// <summary> 1053 /// 移除指定 Key 1054 /// </summary> 1055 /// <param name="keys"></param> 1056 /// <returns></returns> 1057 public long KeyDelete(IEnumerable<string> keys) 1058 { 1059 var redisKeys = keys.Select(x => (RedisKey) AddKeyPrefix(x)); 1060 return _db.KeyDelete(redisKeys.ToArray()); 1061 } 1062 1063 /// <summary> 1064 /// 校验 Key 是否存在 1065 /// </summary> 1066 /// <param name="key"></param> 1067 /// <returns></returns> 1068 public bool KeyExists(string key) 1069 { 1070 key = AddKeyPrefix(key); 1071 return _db.KeyExists(key); 1072 } 1073 1074 /// <summary> 1075 /// 重命名 Key 1076 /// </summary> 1077 /// <param name="key"></param> 1078 /// <param name="newKey"></param> 1079 /// <returns></returns> 1080 public bool KeyRename(string key, string newKey) 1081 { 1082 key = AddKeyPrefix(key); 1083 return _db.KeyRename(key, newKey); 1084 } 1085 1086 /// <summary> 1087 /// 设置 Key 的时间 1088 /// </summary> 1089 /// <param name="key"></param> 1090 /// <param name="expiry"></param> 1091 /// <returns></returns> 1092 public bool KeyExpire(string key, TimeSpan? expiry) 1093 { 1094 key = AddKeyPrefix(key); 1095 return _db.KeyExpire(key, expiry); 1096 } 1097 1098 #region key-async 1099 1100 /// <summary> 1101 /// 移除指定 Key 1102 /// </summary> 1103 /// <param name="key"></param> 1104 /// <returns></returns> 1105 public async Task<bool> KeyDeleteAsync(string key) 1106 { 1107 key = AddKeyPrefix(key); 1108 return await _db.KeyDeleteAsync(key); 1109 } 1110 1111 /// <summary> 1112 /// 移除指定 Key 1113 /// </summary> 1114 /// <param name="keys"></param> 1115 /// <returns></returns> 1116 public async Task<long> KeyDeleteAsync(IEnumerable<string> keys) 1117 { 1118 var redisKeys = keys.Select(x => (RedisKey) AddKeyPrefix(x)); 1119 return await _db.KeyDeleteAsync(redisKeys.ToArray()); 1120 } 1121 1122 /// <summary> 1123 /// 校验 Key 是否存在 1124 /// </summary> 1125 /// <param name="key"></param> 1126 /// <returns></returns> 1127 public async Task<bool> KeyExistsAsync(string key) 1128 { 1129 key = AddKeyPrefix(key); 1130 return await _db.KeyExistsAsync(key); 1131 } 1132 1133 /// <summary> 1134 /// 重命名 Key 1135 /// </summary> 1136 /// <param name="key"></param> 1137 /// <param name="newKey"></param> 1138 /// <returns></returns> 1139 public async Task<bool> KeyRenameAsync(string key, string newKey) 1140 { 1141 key = AddKeyPrefix(key); 1142 return await _db.KeyRenameAsync(key, newKey); 1143 } 1144 1145 /// <summary> 1146 /// 设置 Key 的时间 1147 /// </summary> 1148 /// <param name="key"></param> 1149 /// <param name="expiry"></param> 1150 /// <returns></returns> 1151 public async Task<bool> KeyExpireAsync(string key, TimeSpan? expiry) 1152 { 1153 key = AddKeyPrefix(key); 1154 return await _db.KeyExpireAsync(key, expiry); 1155 } 1156 1157 #endregion key-async 1158 1159 #endregion key 操作 1160 1161 #region 发布订阅 1162 1163 /// <summary> 1164 /// 订阅 1165 /// </summary> 1166 /// <param name="channel"></param> 1167 /// <param name="handle"></param> 1168 public void Subscribe(RedisChannel channel, Action<RedisChannel, RedisValue> handle) 1169 { 1170 var sub = _connMultiplexer.GetSubscriber(); 1171 sub.Subscribe(channel, handle); 1172 } 1173 1174 /// <summary> 1175 /// 发布 1176 /// </summary> 1177 /// <param name="channel"></param> 1178 /// <param name="message"></param> 1179 /// <returns></returns> 1180 public long Publish(RedisChannel channel, RedisValue message) 1181 { 1182 var sub = _connMultiplexer.GetSubscriber(); 1183 return sub.Publish(channel, message); 1184 } 1185 1186 /// <summary> 1187 /// 发布(使用序列化) 1188 /// </summary> 1189 /// <typeparam name="T"></typeparam> 1190 /// <param name="channel"></param> 1191 /// <param name="message"></param> 1192 /// <returns></returns> 1193 public long Publish<T>(RedisChannel channel, T message) 1194 { 1195 var sub = _connMultiplexer.GetSubscriber(); 1196 return sub.Publish(channel, Serialize(message)); 1197 } 1198 1199 #region 发布订阅-async 1200 1201 /// <summary> 1202 /// 订阅 1203 /// </summary> 1204 /// <param name="channel"></param> 1205 /// <param name="handle"></param> 1206 public async Task SubscribeAsync(RedisChannel channel, Action<RedisChannel, RedisValue> handle) 1207 { 1208 var sub = _connMultiplexer.GetSubscriber(); 1209 await sub.SubscribeAsync(channel, handle); 1210 } 1211 1212 /// <summary> 1213 /// 发布 1214 /// </summary> 1215 /// <param name="channel"></param> 1216 /// <param name="message"></param> 1217 /// <returns></returns> 1218 public async Task<long> PublishAsync(RedisChannel channel, RedisValue message) 1219 { 1220 var sub = _connMultiplexer.GetSubscriber(); 1221 return await sub.PublishAsync(channel, message); 1222 } 1223 1224 /// <summary> 1225 /// 发布(使用序列化) 1226 /// </summary> 1227 /// <typeparam name="T"></typeparam> 1228 /// <param name="channel"></param> 1229 /// <param name="message"></param> 1230 /// <returns></returns> 1231 public async Task<long> PublishAsync<T>(RedisChannel channel, T message) 1232 { 1233 var sub = _connMultiplexer.GetSubscriber(); 1234 return await sub.PublishAsync(channel, Serialize(message)); 1235 } 1236 1237 #endregion 发布订阅-async 1238 1239 #endregion 发布订阅 1240 1241 #region private method 1242 1243 /// <summary> 1244 /// 添加 Key 的前缀 1245 /// </summary> 1246 /// <param name="key"></param> 1247 /// <returns></returns> 1248 private static string AddKeyPrefix(string key) 1249 { 1250 return $"{DefaultKey}:{key}"; 1251 } 1252 1253 /// <summary> 1254 /// 转换为字符串 1255 /// </summary> 1256 /// <typeparam name="T"></typeparam> 1257 /// <param name="list"></param> 1258 /// <returns></returns> 1259 private static IEnumerable<string> ConvertStrings<T>(IEnumerable<T> list) where T : struct 1260 { 1261 if (list == null) throw new ArgumentNullException(nameof(list)); 1262 return list.Select(x => x.ToString()); 1263 } 1264 1265 #region 注册事件 1266 1267 /// <summary> 1268 /// 添加注册事件 1269 /// </summary> 1270 private static void AddRegisterEvent() 1271 { 1272 _connMultiplexer.ConnectionRestored += ConnMultiplexer_ConnectionRestored; 1273 _connMultiplexer.ConnectionFailed += ConnMultiplexer_ConnectionFailed; 1274 _connMultiplexer.ErrorMessage += ConnMultiplexer_ErrorMessage; 1275 _connMultiplexer.ConfigurationChanged += ConnMultiplexer_ConfigurationChanged; 1276 _connMultiplexer.HashSlotMoved += ConnMultiplexer_HashSlotMoved; 1277 _connMultiplexer.InternalError += ConnMultiplexer_InternalError; 1278 _connMultiplexer.ConfigurationChangedBroadcast += ConnMultiplexer_ConfigurationChangedBroadcast; 1279 } 1280 1281 /// <summary> 1282 /// 重新配置广播时(通常意味着主从同步更改) 1283 /// </summary> 1284 /// <param name="sender"></param> 1285 /// <param name="e"></param> 1286 private static void ConnMultiplexer_ConfigurationChangedBroadcast(object sender, EndPointEventArgs e) 1287 { 1288 Console.WriteLine($"{nameof(ConnMultiplexer_ConfigurationChangedBroadcast)}: {e.EndPoint}"); 1289 } 1290 1291 /// <summary> 1292 /// 发生内部错误时(主要用于调试) 1293 /// </summary> 1294 /// <param name="sender"></param> 1295 /// <param name="e"></param> 1296 private static void ConnMultiplexer_InternalError(object sender, InternalErrorEventArgs e) 1297 { 1298 Console.WriteLine($"{nameof(ConnMultiplexer_InternalError)}: {e.Exception}"); 1299 } 1300 1301 /// <summary> 1302 /// 更改集群时 1303 /// </summary> 1304 /// <param name="sender"></param> 1305 /// <param name="e"></param> 1306 private static void ConnMultiplexer_HashSlotMoved(object sender, HashSlotMovedEventArgs e) 1307 { 1308 Console.WriteLine( 1309 $"{nameof(ConnMultiplexer_HashSlotMoved)}: {nameof(e.OldEndPoint)}-{e.OldEndPoint} To {nameof(e.NewEndPoint)}-{e.NewEndPoint}, "); 1310 } 1311 1312 /// <summary> 1313 /// 配置更改时 1314 /// </summary> 1315 /// <param name="sender"></param> 1316 /// <param name="e"></param> 1317 private static void ConnMultiplexer_ConfigurationChanged(object sender, EndPointEventArgs e) 1318 { 1319 Console.WriteLine($"{nameof(ConnMultiplexer_ConfigurationChanged)}: {e.EndPoint}"); 1320 } 1321 1322 /// <summary> 1323 /// 发生错误时 1324 /// </summary> 1325 /// <param name="sender"></param> 1326 /// <param name="e"></param> 1327 private static void ConnMultiplexer_ErrorMessage(object sender, RedisErrorEventArgs e) 1328 { 1329 Console.WriteLine($"{nameof(ConnMultiplexer_ErrorMessage)}: {e.Message}"); 1330 } 1331 1332 /// <summary> 1333 /// 物理连接失败时 1334 /// </summary> 1335 /// <param name="sender"></param> 1336 /// <param name="e"></param> 1337 private static void ConnMultiplexer_ConnectionFailed(object sender, ConnectionFailedEventArgs e) 1338 { 1339 Console.WriteLine($"{nameof(ConnMultiplexer_ConnectionFailed)}: {e.Exception}"); 1340 } 1341 1342 /// <summary> 1343 /// 建立物理连接时 1344 /// </summary> 1345 /// <param name="sender"></param> 1346 /// <param name="e"></param> 1347 private static void ConnMultiplexer_ConnectionRestored(object sender, ConnectionFailedEventArgs e) 1348 { 1349 Console.WriteLine($"{nameof(ConnMultiplexer_ConnectionRestored)}: {e.Exception}"); 1350 } 1351 1352 #endregion 注册事件 1353 1354 /// <summary> 1355 /// 序列化 1356 /// </summary> 1357 /// <param name="obj"></param> 1358 /// <returns></returns> 1359 private static byte[] Serialize(object obj) 1360 { 1361 if (obj == null) 1362 return null; 1363 1364 var binaryFormatter = new BinaryFormatter(); 1365 using (var memoryStream = new MemoryStream()) 1366 { 1367 binaryFormatter.Serialize(memoryStream, obj); 1368 var data = memoryStream.ToArray(); 1369 return data; 1370 } 1371 } 1372 1373 /// <summary> 1374 /// 反序列化 1375 /// </summary> 1376 /// <typeparam name="T"></typeparam> 1377 /// <param name="data"></param> 1378 /// <returns></returns> 1379 private static T Deserialize<T>(byte[] data) 1380 { 1381 if (data == null) 1382 return default(T); 1383 1384 var binaryFormatter = new BinaryFormatter(); 1385 using (var memoryStream = new MemoryStream(data)) 1386 { 1387 var result = (T) binaryFormatter.Deserialize(memoryStream); 1388 return result; 1389 } 1390 } 1391 1392 #endregion private method 1393 } 1394 }
下期将分析 redis 的五大类型,及介绍他们常用的指令。
系列
《Redis 小白指南(一)- 简介、安装、GUI 和 C# 驱动介绍》
《Redis 小白指南(二)- 聊聊五大类型:字符串、散列、列表、集合和有序集合》
《Redis 小白指南(三)- 事务、过期、消息通知、管道、优化内存空间》
【博主】反骨仔
【原文】http://www.cnblogs.com/liqingwen/p/6917426.html
【GitHub】https://github.com/liqingwen2015/Wen.Helpers/blob/master/Wen.Helpers.Common/Redis/RedisHelper.cs
【参考】《redis 入门指南》