复习

2021年7月2日 Redis - 图1

  1. redis
    1. 概念: 开源的内存数据结构存储,可以用作数据库、缓存、消息中间件等。
      1. 数据结构:string\hash\set\list\sorted set\bitmap\hyperloglogs\geospatial
      2. 特性:持久化、通过哨兵实现高可用、通过cluster实现自动分区、事务、lua脚本支持、LRU内存清理策略
    2. 安装 yum install -y redis
    3. key相关的命令
      1. set
      2. get
      3. expire pexpire <=> persist
      4. ttl pttl
      5. del
      6. keys
      7. exists
      8. type
      9. rename

String

set 新增或者修改

  • EX 过期时间秒
  • PX 过期时间毫秒
  • NX 新增操作,必须不存在,如果存在则失败
  • XX 修改操作,必须存在,如果不存在则失败

get 获取
mget 一次获取多个key的值
getset
strlen 长度
incr 对数字加一
decr 对数字减一
incrby 对数字加N
decrby 对数字减N
append 追加

  1. mset user:huangguang:degree baobiao user:huangguange:age 18 user:huangguange:gender M
  2. mget user:cyx:degree user:cyx:age user:cyx:gender

使用场景:

  • 统计:在线人数
  • 缓存
  • 分布式锁:排他性,A加锁之后其他人加不了锁
    • set NX 加锁 加过期时间防止死锁 、 value表示加锁者 ```bash 127.0.0.1:6379> set lock:balance:decr james ex 30 OK 127.0.0.1:6379> set lock:balance:decr durant ex 30 NX (nil)
  1. execA set lock lucas ex 30 NX | set lock curry ex 30 NX(失败)<br />execB<br />execC 解锁 | set lock curry ex 30 NX(成功)
  2. - del 解锁 不能直接删除,判断value是否为当前用户,当前用户是否为加锁者 if(val==当前用户){del lock}
  3. - 从获取值到判断时存在一段时间间隔,可能存在并发问题,需要保证判断和删除两个操作的原子性,使用lua脚本封装
  4. <a name="LNLSa"></a>
  5. # Hash K-V结构
  6. ![image.png](https://cdn.nlark.com/yuque/0/2021/png/953441/1625196686545-a28abf8c-ce7d-4122-8bce-dc687cd224b7.png#height=460&id=UvmTc&margin=%5Bobject%20Object%5D&name=image.png&originHeight=460&originWidth=1030&originalType=binary&ratio=1&size=24865&status=done&style=none&width=1030)<br />hset 添加修改<br />hget 获取<br />hmset 添加修改多个字段<br />hmget 获取多个字段<br />hgetall 获取所有字段<br />hincrby 增加某个数字的值,可以为负数<br />hexists 判断是否有字段
  7. ```bash
  8. 127.0.0.1:6379> hset user:cyx age 23
  9. (integer) 1
  10. 127.0.0.1:6379> hset user:cyx score 1000
  11. (integer) 1
  12. 127.0.0.1:6379> hget user:cyx age
  13. "23"
  14. 127.0.0.1:6379> hgetall user:cyx
  15. 1) "age"
  16. 2) "23"
  17. 3) "score"
  18. 4) "1000"
  19. 127.0.0.1:6379> hget user:cyx score
  20. "1000"
  21. 127.0.0.1:6379> hgetall user:cyx
  22. 1) "age"
  23. 2) "23"
  24. 3) "score"
  25. 4) "1000"
  26. 127.0.0.1:6379> hmset user:hg age 18 score 1000 hobby coding
  27. OK
  28. 127.0.0.1:6379> hmget user:hg age score hobby
  29. 1) "18"
  30. 2) "1000"
  31. 3) "coding"
  32. 127.0.0.1:6379> hincrby user:hg age 10
  33. (integer) 28
  34. 127.0.0.1:6379> hincrby user:hg age -5
  35. (integer) 23
  36. 127.0.0.1:6379> hexists user:hg age
  37. (integer) 1
  38. 127.0.0.1:6379> hexists user:hg honor
  39. (integer) 0
  40. 127.0.0.1:6379> hexists user:hg lunch
  41. (integer) 0
  42. 127.0.0.1:6379> hkeys user:hg
  43. 1) "age"
  44. 2) "score"
  45. 3) "hobby"
  46. 127.0.0.1:6379> hvals user:hg
  47. 1) "23"
  48. 2) "1000"
  49. 3) "coding"
  50. 127.0.0.1:6379> hlen user:hg
  51. (integer) 3

使用场景:

  1. 缓存,存对象
  2. 短网址生成器 短网址<=>真实网址
  3. 用户登录存储
  4. 手机验证码,带过期时间
  5. List

    image.png
    image.png
    LPUSH 加入,从尾部加入
    RPUSH
    LINSERT 插入
    lset
    LPOP 弹出,从头部取出
    RPOP
    LREM key count element
    删除等于element的元素
    删除count次
    count如果>0 从左往右 头到尾
    count<0 从右往左 尾到头
    count=0 删除所有
    LLEN
    lrange ```bash lpush eat pty hqh ls fg

lrange eat 0 -1 rpush eat cyx

linsert eat AFTER hqh zyq linsert eat BEFORE hqh pyy lpop eat lindex eat 1

lrem eat 3 pty

  1. <a name="ceJa8"></a>
  2. ## 使用场景
  3. 1. 队列数据结构: 消息队列
  4. 1. 分页查询:lrange
  5. <a name="xCu1K"></a>
  6. # Set
  7. sadd 添加<br />spop 随机删除<br />srandmember 随机取出<br />scard 统计个数<br />sdiff k1 k2 从第一个减去其他的集合<br />sinter k1 k2 取得交集,都有元素<br />sunion k1 k2 取并集,将所有不同的元素合并<br />sdiffstore sinterstore sunionstore 将计算出的结果存入新的集合<br />smove 原始集合 目标集合 元素 移动到另一个集合中<br />sismember 判断是否在集合中
  8. <a name="JyaPD"></a>
  9. ## 使用场景
  10. 1. 社交网络:共同好友,共同关注,共同爱好....
  11. 1. 唯一计数器:去重特性
  12. 1. 标签:
  13. 1. 点赞、投票
  14. 1. 随机点名
  15. <a name="5mGOF"></a>
  16. # SortedSet
  17. zadd 元素需要一个分数 zadd products 1000 wahaha 300 cokecola 299 pepsicola<br />zrange 默认升序排序<br />zrevrange 默认降序 zrevrange products 0 3<br />zrangebyscore 返回分数,升序<br />zrevrangebyscore 返回分数,降序<br />zcount products 300 10000 分数在区间范围内的数量<br />zrank products cokecola 排名<br />zscore products wahaha 得到对应的分数
  18. <a name="R1kVU"></a>
  19. ## 使用场景
  20. - 排行榜
  21. - 时间线,将时间转换为毫秒,按时间排序
  22. <a name="CAQFH"></a>
  23. # Redis使用规范
  24. [https://developer.aliyun.com/article/531067](https://developer.aliyun.com/article/531067)
  25. keys \flushall \config 不能使用<br />vim /etc/redis.conf
  26. ```bash
  27. rename-command flushall ""
  28. rename-command flushdb ""
  29. rename-command keys ""

Scan

SCAN cursor [MATCH pattern] [COUNT count]
cursor 游标,特殊游标0表示开始迭代
match 匹配规则, glob风格(=所有,?=单个字符…)
count 限制最大返回数量
循环按批取出所有数据
scan 0 match user:
count 10
返回两个元素的数组,第一个元素是下一次迭代的游标 第二元素是本次迭代的数据
下一次迭代时用 上一次的游标;当游标再次返回0时,表示迭代结束
full iteration :以 0 作为游标开始一次新的迭代, 一直调用 SCAN 命令, 直到命令返回游标 0 , 我们称这个过程为一次完整遍历。

  1. 127.0.0.1:6379> set user:cyx:energy low
  2. OK
  3. 127.0.0.1:6379> set user:zzq:energy low
  4. OK
  5. 127.0.0.1:6379> set user:fg:energy 0
  6. OK
  7. 127.0.0.1:6379> set user:djx:energy low
  8. OK
  9. 127.0.0.1:6379> set user:yxd:energy high
  10. OK
  11. 127.0.0.1:6379> set a b
  12. OK
  13. 127.0.0.1:6379> set c d
  14. OK
  15. 127.0.0.1:6379> scan 0 match user:* count 10
  16. 1) "0"
  17. 2) 1) "user:fg:energy"
  18. 2) "user:yxd:energy"
  19. 3) "user:djx:energy"
  20. 4) "user:cyx:energy"
  21. 5) "user:zzq:energy"
  22. 127.0.0.1:6379> scan 0 match user:* count 3
  23. 1) "6"
  24. 2) 1) "user:fg:energy"
  25. 2) "user:yxd:energy"
  26. 127.0.0.1:6379> scan 6 match user:* count 3
  27. 1) "7"
  28. 2) 1) "user:djx:energy"
  29. 2) "user:cyx:energy"
  30. 3) "user:zzq:energy"
  31. 127.0.0.1:6379> scan 7 match user:* count 3
  32. 1) "0"
  33. 2) (empty list or set)
  34. 127.0.0.1:6379> scan 6 match user:* count 3
  35. 1) "7"
  36. 2) 1) "user:djx:energy"
  37. 2) "user:cyx:energy"
  38. 3) "user:zzq:energy"
  39. 127.0.0.1:6379> scan 7 match user:* count 3
  40. 1) "0"
  41. 2) (empty list or set)
  42. 127.0.0.1:6379> scan 7 match user:* count 2
  43. 1) "0"
  44. 2) (empty list or set)
  45. 127.0.0.1:6379> scan 0 match user:* count 2
  46. 1) "2"
  47. 2) 1) "user:fg:energy"
  48. 127.0.0.1:6379> scan 2 match user:* count 2
  49. 1) "1"
  50. 2) 1) "user:yxd:energy"
  51. 127.0.0.1:6379> scan 1 match user:* count 2
  52. 1) "7"
  53. 2) 1) "user:djx:energy"
  54. 2) "user:cyx:energy"
  55. 3) "user:zzq:energy"
  56. 127.0.0.1:6379> scan 7 match user:* count 2
  57. 1) "0"
  58. 2) (empty list or set)
  59. 127.0.0.1:6379> sadd stus wangyang tangxiao xiongwei suhaoran yuexiaodong liuyouli chenyang dingyi
  60. (integer) 8
  61. 127.0.0.1:6379> sscan stus 0
  62. 1) "0"
  63. 2) 1) "yuexiaodong"
  64. 2) "liuyouli"
  65. 3) "dingyi"
  66. 4) "xiongwei"
  67. 5) "suhaoran"
  68. 6) "wangyang"
  69. 7) "chenyang"
  70. 8) "tangxiao"
  71. 127.0.0.1:6379> sscan stus 0 count 3
  72. 1) "5"
  73. 2) 1) "yuexiaodong"
  74. 2) "liuyouli"
  75. 3) "dingyi"
  76. 4) "xiongwei"
  77. 5) "suhaoran"
  78. 127.0.0.1:6379> sscan stus 5 count 3
  79. 1) "0"
  80. 2) 1) "wangyang"
  81. 2) "chenyang"
  82. 3) "tangxiao"
  83. 127.0.0.1:6379>

Java连接Redis

1. Jedis 基础驱动

  1. 建的maven的quickstart项目,加依赖

    1. <dependency>
    2. <groupId>redis.clients</groupId>
    3. <artifactId>jedis</artifactId>
    4. <version>2.8.1</version>
    5. </dependency>
  2. 编码 ```java package com.woniuxy.redis;

import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool;

/**

  • Hello world! / public class App { public static void main( String[] args ) {

    1. //建立链接
    2. JedisPool jedisPool = new JedisPool("localhost", 6379);
    3. Jedis jedis = jedisPool.getResource();
    4. //发送指令
    5. if(!jedis.exists("stus")) {
    6. jedis.sadd("stus", "邓继鑫", "董海川", "丁懿", "陈扬", "刘又溧", "程昱翔", "杨林", "白秋洋", "田杰仁", "乐小东", "傅刚", "彭淘沿", "胡启昊", "黄小渝", "杜罗乐", "栗浩然", "谭宪军", "黄煜", "熊威", "彭亿元", "周橘恒", "熊春林", "唐肖", "周友强", "朱志强", "黄广", "王阳", "彭章明", "杨文", "甘可可", "徐阳", "彭川弋", "严川", "廖松", "汪界行");
    7. }
    8. String theOne = jedis.srandmember("stus");
    9. System.out.println("天之骄子:"+theOne);
    10. //清理关闭
    11. jedis.close();
    12. jedisPool.close();

    } }

  1. <a name="ZMMB9"></a>
  2. ## 2. spring-data-redis 高级封装
  3. [https://spring.io/projects/spring-data-redis](https://spring.io/projects/spring-data-redis)<br />1. 建项目 选择 spring-web lombok spring-data-redis<br />2.编码
  4. - RedisTemplate
  5. - opsForXXX 针对于XXX类型的操作
  6. - boundXXXOps
  7. ```java
  8. package com.woniuxy.redis.redisbootdemo.controller;
  9. import lombok.extern.slf4j.Slf4j;
  10. import org.springframework.beans.factory.annotation.Autowired;
  11. import org.springframework.data.redis.core.*;
  12. import org.springframework.web.bind.annotation.GetMapping;
  13. import org.springframework.web.bind.annotation.RestController;
  14. import java.util.Set;
  15. @RestController
  16. @Slf4j
  17. public class StudentController {
  18. @Autowired
  19. private RedisTemplate redisTemplate;
  20. @GetMapping("dm")
  21. public String callTheRoll() {
  22. //String操作
  23. ValueOperations ops = redisTemplate.opsForValue();
  24. ops.set("qbzs", "cyx");
  25. // ops.setIfAbsent();//如果不存在,则设置 set NX
  26. // ops.setIfPresent()//如果存在,则设置 set XX
  27. //Hash操作
  28. HashOperations hashOps = redisTemplate.opsForHash();
  29. //hset user:1 age 23
  30. hashOps.put("user:1", "age", 23);
  31. //Set操作
  32. SetOperations setOps = redisTemplate.opsForSet();
  33. if(!redisTemplate.hasKey("stusboot")){
  34. setOps.add("stusboot", "邓继鑫", "董海川", "丁懿", "陈扬", "刘又溧", "程昱翔", "杨林", "白秋洋", "田杰仁", "乐小东", "傅刚", "彭淘沿", "胡启昊", "黄小渝", "杜罗乐", "栗浩然", "谭宪军", "黄煜", "熊威", "彭亿元", "周橘恒", "熊春林", "唐肖", "周友强", "朱志强", "黄广", "王阳", "彭章明", "杨文", "甘可可", "徐阳", "彭川弋", "严川", "廖松", "汪界行");
  35. }
  36. Object theOne = setOps.randomMember("stusboot");
  37. log.info("天之骄子 : {}",theOne);
  38. //boundXXXOps 绑定一个KEY,后续操作无须带key
  39. BoundZSetOperations zSetOps = redisTemplate.boundZSetOps("products");
  40. zSetOps.add("wahaha",1000);
  41. zSetOps.add("tianfukele",200);
  42. zSetOps.add("jianlibao",300);
  43. Set set = zSetOps.reverseRange(0, zSetOps.size());
  44. log.info("排名情况:{}",set);
  45. return "天之骄子 :"+theOne;
  46. }
  47. }

Redisson

作业

  1. 整理笔记
  2. 完成以下redis题

Redis场景解答设计和代码 模版.docx