美文网首页
Redis常用数据结构使用场景说明和命令示例(非常实用)

Redis常用数据结构使用场景说明和命令示例(非常实用)

作者: 运气爆棚lsw | 来源:发表于2023-02-19 22:35 被阅读0次

    Redis常用的数据结构以及各种数据结构使用场景示例(非常实用)


    1、String数据结构

    SET key value
    // 存入字符串键值对

    MSET key value [key value ...]
    // 批量存储字符串键值对

    SETNX key value
    // 存入一个不存在的字符串键值对

    GET key
    // 获取字符串键值

    MGET key [key ...]
    // 批量获取字符串键值

    DEL key [key ...]
    // 删除一个键

    EXPIRE key seconds
    // 设置一个key的过期时间(秒)

    原子性加减命令:
    INCR key
    // 将key中储存的数字值加1

    DECR key
    // 将key中储存的数字值减1

    INCRBY key increment
    // 将key中值加上increment

    DECRBY key increment
    // 将key中值减去increment

    --增
    set mykey "test"       --为键设置新值,并覆盖原有值
    setex mykey 10 "hello" -- 设置指定 Key 的过期时间为10秒,在存活时间可以获取value
    mset key3 "stephen" key4 "liu" --批量设置键
    --删
    del mykey --删除已有键
    --改
    incr mykey      --值增加1,若该key不存在,创建key,初始值设为0,增加后结果为1
    decrby mykey 5  --值减少5
    --查 
    exists mykey   --判断该键是否存在,存在返回 1,否则返回0
    get mykey      --获取Key对应的value
    mget key3 key4 --批量获取键
    
    
    使用场景:
    1、key/value单值缓存

    SET key value
    GET key
    商品库存 key商品ID value商品的实际库存

    2、对象缓存

    SET user:1 value(JSON格式数据)

    3、分布式锁

    命令 SETNX key value
    当且仅当key不存在的时候执行操作,否则不执行任何操作

    SETNX produce:10001 true
    // 返回1代表获取锁成功
    // 返回0代表获取锁失败
    。。。执行业务操作。。。
    DEL product:10001
    // 执行完业务释放锁

    SET product:10001 true ex 10 nx
    // 防止程序意外终止导致死锁

    4、原子计数器

    比如博客,文章有个阅读数
    只要文章被打开,我即可执行一条
    INCR article:readCount:{文章ID}命令

    INCR article:readCount:{文章ID}
    // 每次执行一次key+1

    GET article:readCount:{文章ID}
    // 获取当前key的值

    5、分布式系统全局序列号

    INCRBY orderId 100
    // redis批量生成序列号,提升性能

    问题:频繁执行Redis命令会增加Redis机器的性能压力,这个时候可以考虑使用批量生成,然后在服务内存里面缓存起来使用

    2、Hash数据结构

    Hash的常用操作:

    HSET key field value
    // 存储一个哈希表key的键值

    HSETNX key field value
    // 存储一个不存在的哈希表的key键值

    HMSET key field value [field value ...]
    // 在一个Hash表中存储多个键值对

    HGET key field
    // 获取哈希表key对应的field的键值

    HMGET key field [field ...]
    // 批量获取哈希表key对应field的多个键值

    HDEL key field [field ...]
    // 批量删除哈希表key对应的field的多个键值

    HLEN key
    // 返回哈希表key中field的数量

    HGETALL key
    // 返回哈希表key中所有的键值

    HINCRBY key field increment
    // 为哈希表key中field的键的值添加增量 increment

    hset cart:{用户id} {商品id} 1  # 添加商品
    
    hincrby cart:{用户id} {商品id} 1 # 增加数量
    
    hlen cart:{用户id} # 获取商品总数
    
    hdel cart:{用户id} {商品id} # 删除商品
    
    hgetall cart:{用户id} #获取购物车所有商品
    
    
    --增
    hset key field1 "s"   --若字段field1不存在,创建该键及与其关联的Hash, Hash中,key为field1 ,并设value为s ,若字段field1存在,则覆盖 
    hmset key field1 "hello" field2 "world" -- 一次性设置多个字段    
    --删
    hdel key field1 --删除 key 键中字段名为 field1 的字段
    del key  -- 删除键    
    --改 
    hincrby key field 1 --给field的值加1
    --查
    hget key field1 --获取键值为 key,字段为 field1 的值
    hlen key        --获取key键的字段数量
    hmget key field1 field2 field3 --一次性获取多个字段
    hgetall key --返回 key 键的所有field值及value值
    hkeys key   --获取key 键中所有字段的field值
    hvals key   --获取 key 键中所有字段的value值
    
    
    Hash应用场景:
    ①对象缓存存储命令:

    HMSET user {userId}:name 张三 {userId}:balance 18

    存储数据库对象数据,使用示例如下:
    HMSET user 1:name 赵思 1:balance 180
    HMSET user 2:name 王五 2:balance 190
    问题:
    hash最重要存储对象数据,当某个值频繁被修改时,非常方便。比如用户积分,只需要操作积分的file数据即可,对象其他数据值不会受到影响

    ②电商购物车

    1、以用户唯一ID为哈希表的key
    2、以购买商品的唯一ID为field
    3、商品购买数量为value

    购物车操作:HSET cert:{用于ID} {商品ID} {购买数量}
    1、添加商品

    HSET cert:1001 2080 1

    2、增加商品数量

    HINCRBY cert:1001 2080 2

    3、商品总数

    HLEN cert:1001

    4、删除商品

    HDEL cert:1001 2080

    5、获取购物车里的所有商品

    HGETALL cert:1001

    注意:展示的商品详情,通过ID去查询然后展示数据

    3、list列表数据结构

    LPUSH key value [value ...]
    将一个或多个值value插入到ley列表的表头(最左边)

    RPUSH key value [value ...]
    将一个或多个值value插入到ley列表的表头(最右边)

    LPOP key
    移除并返回key列表的头元素

    RPOP key
    移除并返回key列表的尾元素

    LRANGE key start stop
    返回列表key中指定区间内的元素,区间以偏移量start和stop指定,注意从0开始

    BLPOP key [key ...] timeout
    从key列表的表头弹出一个元素,所列表中没有元素,阻塞等待timeout秒,如果timeout=0则一直阻塞等待

    BRPOP key [key ...] timeout
    从key列表的表尾弹出一个元素,若列表中没有元素,阻塞等待timeout秒,如果timeout=0则一直阻塞等待


    --增 
    lpush mykey a b --若key不存在,创建该键及与其关联的List,依次插入a ,b, 若List类型的key存在,则插入value中
    rpush mykey a b --在链表尾部先插入b,在插入a(lpush list a b那么读的时候是b,a的顺序,而rpush是怎么放怎么读出来
    --删
    del mykey       --删除已有键 
    --改
    lset mykey 1 e        --从头开始, 将索引为1的元素值,设置为新值 e,若索引越界,则返回错误信息
    --查
    lrange mykey 0 -1 --取链表中的全部元素,其中0表示第一个元素,-1表示最后一个元素。
    lrange mykey 0 2  --从头开始,取索引为0,1,2的元素
    lpop mykey        --获取头部元素,并且弹出头部元素,出栈
    
    
    List使用场景
    常用分布式数据结构:
    1、Stack栈 = LPUSH + LPOP

    栈数据结构,先进后出

    2、Queue队列 = LPUSH+ RPOP

    队列数据结构,先进先出

    3、Blocking MQ(阻塞队列) = LPUSH +BPROP

    注意:BPROP可以实现阻塞 B->block

    4、微博,微信公众号订阅消息流

    (几万以下粉丝适合)
    给每个用户,创建一个List接收消息列表,
    然后发布的文章添加到用户的List数据结构中去,同时默认是拍好序号的数据,直接使用
    LRANG msg:{微博ID} 0 5
    则可以取出6条数据,这样用户访问的性能就很高
    (注意:对于特别多订阅用户不适合)

    超级大V,应该使用什么方案呢?

    4、Set集合数据结构

    Set常用操作:

    SADD key member [member ...]
    向集合key中存入元素。元素存在则忽略
    可以批量的放元素

    SREM key member [member ...]
    从集合key中删除元素

    SCARD key
    获取集合key的元素个数

    SISMEMBER key member
    判断member元素是否存在于集合key中

    SRANDMEMBER key [count]
    从集合key中选出count个元素,元素不从key中删除

    SPOP key [count]
    从集合key中选出count个元素,元素从key中删除

    Set运算操作:

    SINTER key [key ...]
    交集运算

    SINTERSTORE destination key [key...]
    将交集结果存入新的集合destination中

    SUNION key [key ...]
    并集运算

    SUNIONSTORE destination key [key ...]
    将并集结果存入新的集合destination中

    SDIFF key [key ...]
    差集运算

    SDIFFSTORE destination key [key ...]
    将差集结果存入新的集合destination中

    --增
    sadd myset a b c --若key不存在,创建该键及与其关联的set,依次插入a ,b,c。若key存在,则插入value中,若a 在myset中已经存在,则插入了 b 和 c 两个新成员。
    
    --删
    spop myset       --尾部的b被移出,事实上b并不是之前插入的第一个或最后一个成员
    srem myset a d f --若f不存在, 移出 a、d ,并返回2
    
    --改
    smove myset myset2 a --将a从 myset 移到 myset2,
    
    --查
    sismember myset a --判断 a 是否已经存在,返回值为 1 表示存在。
    smembers myset    --查看set中的内容
    scard myset       --获取Set 集合中元素的数量
    srandmember myset --随机的返回某一成员
    
    
    Set数据结构使用场景:
    1、微信抽奖小程序
    ①点击参与抽奖加入集合

    SADD key {userID}
    示例:活动act:001参与用户2001、2002
    sadd act:001 2001
    sadd act:001 2002

    ②查看参与抽奖所有用户

    SMEMBERS key
    示例:
    SMEMBERS act:001
    展示所有参与抽奖用户userId

    ③抽取count名抽奖者

    SRANDMEMBER key [count]
    从集合中随机拿出count个元素

    SPOP key [count]
    从集合中拿出元素并删除元素
    比如抽奖后不能再参与抽奖了

    使用场景:
    微信微博点赞,收藏,标签
    1、点赞

    SADD like:{消息ID} {用户ID}

    2、取消点赞

    SREM like:{消息ID} {用户ID}

    3、检查用户是否点过赞

    SISMEMBER like:{消息ID} {用户ID}

    4、获取点赞的用户列表

    SISMEMBERS like:{消息ID}

    5、获取点赞的用户数

    SCARD like:{消息ID}

    关注模型:比如共同关注,你的朋友也关注了它

    5、ZSet支持排序的有序集合数据结构

    ZSET常用操作:

    ZADD key score member [ [score member] ... ]
    向有序集合key中加入带分值的元素

    ZREM key member [member ...]
    从有序集合中删除元素

    ZSCORE key member
    返回有序集合key中元素member的分值

    ZINCRBY key increment member
    为有序集合key中元素member的分值加上increment

    ZCARD key
    返回有序集合key中元素个数

    ZRANGE key start stop [WITHSCORES]
    正序获取有序集合key从start下标到stop下标的元素

    ZREVRANGE key start stop [WITHSCORES]
    倒序获取有序集合key从start下标到stop下标的元素

    ZSET的集合操作:
    ZUNIONSTORE destkey numkeys key [key ...]
    并集计算

    ZINTERSTORE destkey numkeys key [key ...]
    交集计算

    --增
    zadd key 2 "two" 3 "three" --添加两个分数分别是 2 和 3 的两个成员
    --删
    zrem key one two  --删除多个成员变量,返回删除的数量
    --改
    zincrby key 2 one --将成员 one 的分数增加 2,并返回该成员更新后的分数(分数改变后相应它的index也会改变)
    --查 
    zrange key 0 -1 WITHSCORES --返回所有成员和分数,不加WITHSCORES,只返回成员
    zrange key start stop --按照元素的分值从小到大的顺序返回从start 到stop之间的所有元素
    zscore key three --获取成员 three 的分数
    zrangebyscore key 1 2 --获取分数满足表达式 1 < score <= 2 的成员
    zcard key       --获取 myzset 键中成员的数量
    zcount key 1 2  --获取分数满足表达式 1 <= score <= 2 的成员的数量
    zrank key member --获取元素的排名,从小到大
    zrevrank key member --获取元素的排名,从大到小
    
    
    使用场景
    1、ZSET点赞按照时间排序
    2、ZSET集合操作实现排行榜
    ①点击新闻增加阅读数

    ZINCRBY hotNews:20220103 1 领导实地考察

    ②展示当日排行前十(取出ZSET前10个元素)

    ZREVRANGE hotNews:20220918 0 9 WITHSCORES

    ③七日搜索榜单计算(求并集)

    ZUNIONSTORE hotNews:202200813-202200819 7
    hotsNews:202200813 hotsNews:202200814 hotsNews:202200815
    hotsNews:202200816 hotsNews:202200817 hotsNews:202200818
    hotsNews:202200819

    ④展示七日排行前十

    ZREVRANGE hotNews:202200813-202200819 0 9 WITHSCORES

    6、Geospatial主要存储经纬度数据

    Redis 在 3.2 推出 Geo 类型,该功能可以推算出地理位置信息,两地之间的距离。

    7、HyperLogLogs

    用于大数据量基数统计,速度非常快,占用内存非常小。每个HyperLogLog键只需要花费12KB内存,就可以计算接近 2^64个不同元素的基数。比如计算网站UV(User view,用户访问数量,一个用户一天访问同一个URL地址多次合并为一次)。

    HyperLogLog常用于大数据量的统计:
    1、页面访问量统计或者用户访问量统计

    2、统计注册 IP 数

    3、统计每日访问 IP 数

    4、统计页面实时 UV 数

    5、统计在线用户数

    6、统计用户每天搜索不同词条的个数

    说明:基数不大,数据量不大就用不上,会有点大材小用浪费空间
    有局限性,就是只能统计基数数量,而没办法去知道具体的内容是什么
    bitmap相比,属于两种特定统计情况,简单来说,HyperLogLog 去重比 bitmap 方便很多

    一般可以bitmap和hyperloglog配合使用,bitmap标识哪些用户活跃,hyperloglog计数

    8、bitmap

    1、用户签到
    很多网站都提供了签到功能,并且需要展示最近一个月的签到情况,这种情况可以使用 BitMap 来实现。
    根据日期 offset = (今天是一年中的第几天) % (今年的天数),key = 年份:用户id。

    如果需要将用户的详细签到信息入库的话,可以考虑使用一个一步线程来完成。

    2、统计用户活跃数
    使用日期作为 key,然后用户 id 为 offset,如果当日活跃过就设置为1。具体怎么样才算活跃这个标准大家可以自己指定。

    假如 20201009 活跃用户情况是: [1,0,1,1,0]
    20201010 活跃用户情况是 :[ 1,1,0,1,0 ]

    统计连续两天活跃的用户总数:
    bitop and dest1 20201009 20201010 
    # dest1 中值为1的offset,就是连续两天活跃用户的ID
    bitcount dest1
    
    统计20201009 ~ 20201010 活跃过的用户:
    bitop or dest2 20201009 20201010 
    

    3、统计用户是否在线
    如果需要提供一个查询当前用户是否在线的接口,也可以考虑使用 BitMap 。即节约空间效率又高,只需要一个 key,然后用户 id 为 offset,如果在线就设置为 1,不在线就设置为 0。
    4、实现布隆过滤器

    参考链接:谈谈Redis五种数据结构及真实应用场景

    相关文章

      网友评论

          本文标题:Redis常用数据结构使用场景说明和命令示例(非常实用)

          本文链接:https://www.haomeiwen.com/subject/cobikdtx.html