提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
前言
今天来介绍一下,redis的各个数据结构以及他们的使用场景。本人水平有限,如有误导,欢迎斧正,一起学习,共同进步!
一、redis的8种数据类型?
redis中一共有8种数据类型,有5种基本数据类型和3种特殊数据类型
基本数据类型:String、List(集合)、Set(集合)、ZSet(有序集合)、Hash(哈希)
特殊数据类型:geospatial(地理位置)、hyperloglog(优点:占用内存小)、Bitmap(位图)
1、string类型
string类型中,可以存储字符串、数字、二进制(bit)。常用命令如下:
set key value ex 10 nx 是setnx key value;expire key 10 的整合。代表10秒过期。
incr key 自动对key的value 进行加1的操作,value必须是数字类型
decr key
incrby key num 自动对key的value进行,value+num 在赋值给value的操作,
decrby key num
2、hash类型
string于hash是最常用的,hash的结构是 key-filed-value 这种格式的。常用命令如下:
hset 存入一个 key filed value 的散列结构
hsetnx 存入一个 key field value ,若key已经存在,则操作失败,不存在,成功
hget 获取指定的key
hmset 批量存入 key field
hmget 批量获取 key field
hdel 删除指定的 key field
hincrby 对key field的数值,进行加减操作
3、list类型
常用命令如下:
lpush key value [value ...] 往key的列表键中左边放入一个元素,key不存在则新建
rpush key value [value ...] 往key的列表键中右边放入一个元素,key不存在则新建
lpop key 从key的列表键最左端弹出一个元素
rpop key 从key的列表键最右端弹出一个元素(从列表中删除)
lrange key start stop 获取列表键从 start 下标到 stop 下标的元素 lrange key 0 -1 全部
blpop key[key...] timeout 阻塞的从key的列表键最左端弹出一个元素,若列表键中不存在元素,
阻塞的等待{timeout}秒,若{timeout}=0,一直阻塞
brpop key[key...] timeout 阻塞的从key的列表键最右端弹出一个元素,若列表键中不存在元素,
阻塞的等待{timeout}秒,若{timeout}=0,一直阻塞
4、set类型
常用命令如下:
sadd key member [member...] 往集合键key中存放元素,做key不存在,则新增
srem key member [member...] 从集合键key中删除元素 (srem sremove 删除的意思)
smembers key 获取集合键key中所有元素
scard key 获取集合键key的元素个数
sismember key member 判断member元素是否存在于集合键key中
srandmember key [count] 从集合键key中选出{count}元素,不从集合键中删除
spop key [count] 从集合键key中选出{count}元素,并且从集合键中删除
count是个数,代表从key中删除这么多个元素(随机删)。redis3.2以后的版本支持该命令
SET 的话,还能:
交集运算:
sinter key [key...]
sinterstore destination key [key...]
并集运算:
sunion key [key...]
sunionstore destination key [key...]
差集运算:
sdiff key [key...]
sdiffstore destination key [key...]
假设 有三个set
set1 a、b、c
set2 b、c、d
set3 c、d、e
则
sinter set1 set2 set3 c
sinterstore destination set1 set2 set3 : 将set1、2、3的并集set进key值叫 destination 里面
sunioin set1 set2 set3 a、b、c、d、e
sdiff set3 set2 set1 e (这个是有参照物的,set3 和 set2 相比的话,有e是set2中没有的。在跟set1相比,set1也没有e,所以是e)
5、zset类型的命令
zadd key score element [...] 往有序集合键key中存放元素,score是分值,element是元素。若key不存在,则新建
zrem key element [...] 往有序集合键key中删除元素
zscore key element 获取有序集合键key中element元素的score值
zincrby key increment element 给有序集合key中的element元素进行score值操作,
increment的值可以是正数,可以是负数。若key不存在则新建,element元素不存在则新增后进行score操作
zcard key 获取有序集合key中的元素个数
zrange key start stop [withscores] 正序获取有序集合key从start下标到stop下标的元素。
加上后面的 withscores 则会将对应的分值也打印,不加的话,只会打印出开元素
zrevrange key start stop [withscores] 倒序获取有序集合key从start下标到stop下标的元素
集合运算操作
zunionstore destkey numkeys key [key..] 并集计算 (非常常用)
zinterstore destkey numkeys key [key..] 交集计算 (并不常用)
6、geospatial & hyperloglog & Bitmap
顾名思义。geospatial 是地理位置,hyperloglog是log,Bitmap 是位图。其中 hyperloglog 的一大特点是占用内存小。
二、使用场景
1、string类型
- 数据缓存,加快响应时间,提高用户体验。
- 分布式锁(这个可以参照下面的“string比hash的优点 3 ”)
string与hash几乎是最常用的,这里就不多做介绍了
2、hash类型
- 购物车功能
添加 hincrby {userId} : shoppingCart {goodsId} {count}
查询 hget {userId} : shoppingCart
意思是说,每个用户都有自己的购物车(所以把购物车当做key),购物车里面的每个商品,当做 hash结构的field; 每个商品的数量,当做 hash结构的value。要是用户对同一个商品,件数选的2的话,就将value加1即可。因为是用户id和商品id,所以像商品单价,商品名称之类的,都可以拿到。 - 菜单数据的缓存
比如说,你的菜单有,ics-km系统和ics-customer系统,每个系统下面都有各自的类型,各自类型的值。比如说ics-km系统的渠道有官网、支付宝、微信、拼多多、小程序等。你就可以用hash结构 key-field-value 结构中,key是ics-km,field是支付宝,value是0。代码如下(示例):
hset ics-km-channel Alipay 0 Wechat 1
3、list类型
-
可以实现消息的队列。因为他有一个命令叫做 blpop key timeout。阻塞的等待timeout秒。可以用provider往队列中插入消息,consumer阻塞的从队列中消费消息,虽然不像专门的消息队列那样,有顺序性、持久性的解决方案,但是也能实现这个功能(需要从别的地方限制)
-
可以实现,关注的列表的最新的消息。比如说,你关注的人有张三、李四,俩人。那你 2021.8.3 看的时候,应该是推送的 2021.8.3 的内容;你 2021.8.4 看的时候,应该推送的就是 2021.8.4 的消息了。那么怎么实现,最新的消息,放在最前面呢?可以用redis的 rpush key v 来实现,往最前面推送最新的消息。
4、set类型
- 比如说是抽奖。微博有博主说,你转发我的微博,我随机抽奖。(或者是刷礼物抽奖什么的),比如说,谁转发了你的微博,你就 sadd key userid,将这个用户id添加到这个key里面。然后第二个人转发了,在把第二个人的用户id添加到这个key里面。最后,该抽奖的时候,看你的规则了,如果是一个人只能中一个奖,你就 spop key 2 。(此处假设二等奖有2人,就随机抽2人中奖,并且中奖后就从这个key中移出来了)。若是可以重复中间,你可以 srandmember key 3 ,随机抽3人中奖,并且中奖后,中奖人员仍在key里面,仍可以参与下次抽奖。
- 可以做点赞、签到、我收藏的知识…等等
比如说用户1001点赞了 标识是8001的帖子,可以: SADD like_8001 1001
用户又取消了点赞: SREM like_8001 1001
检查用户1001是否点赞过 SISMEMBER like_8001 1001
获取帖子8001的点赞过的用户 SMEMBERS like_8001
获取帖子8001的点赞用户总数 SCARD like_8001
- 可以用作 用户推荐、商品推荐等等(比如说抖音的 可能关注的人)
张三(关注的人有): zhangSub --> {li,wang,zhao}
李四: liSub --> {zhang,wang,zhao,tian}
王五: wangSub --> {zhang,li,zhao,tian}
张三打开李四的主页
张三和李四的共同关注: SINTER zhangSub liSub --> {wang,zhao}
张三关注的人中也关注着他(互相关注) SISMEMBER wangSub li、SISMEMBER zhaoSub li、.. (把张三的关注人全部遍历一遍,看看关注人的关注列表中有没有张三)
张三可能认识的人 SDIFF liSub zhangSub --> {zhang,li} // 因为张三进李四的主页,给张三推荐可能认识的人,就把李四的关注有的,张三的关注没有的,推荐给张三
5、zset类型
- 单日排行榜(新闻的热榜啊,知识的热榜啊什么的)。比如说,你新建一个zset的key:
zadd hostNewId_date 1 newId // 新建一个 热点新闻id_日期 1 新闻id 的key
zincrby hostNewId_date 1 newId // 每次被点击时加1
zrevrange hostNewId_date 0 15 withscores // 拿到热榜的前15个,并展示数值。 - 周榜、月榜、年榜等排行榜。比如说,你是用的 知识Id_日期 当做redis的zset的key,那么统计周榜的时候,就是用 zunionstore 合并后的key名 7 key1…key
7 (zunionstore是固定的,合并后的key是随便起的,7是key的个数,后面是每个key的值) 统计出来7天的key,然后用 zrevrange key 0 10 拿到前10条数据。同样的能拿到月榜、年榜。
三、其他
1、hash 比 string 的优点?
1、可以将信息凝聚在一起,便于管理
2、从一定程度上可以避免误操作,减少key冲突
3、减少内存/io/cpu 的消耗(这点是说,redis是针对于key的扫描,检索,ttl过期之类的都是针对于这个key的,虽然这个key里面有多个field,但是还是只有一个key。若是使用字符串的话,要想达成同样的目的,则会产生大量的key,会产生大量的key的一个扫描,而使用一个key的话,会减少最外层的key的,cpu的消耗。比如说key是冲突啊,对key的管理啊什么的,一个key所消耗的资源肯定比多个key所消耗的资源少)
2、string 比 hash 的优点?
1、hash的field,是没有过期的功能的。他只能设置key的过期时间,不能给单独的某个field设置过期时间(所以redis的hash是不能用做分布式锁的,只能是string来当分布式锁)
2、hash 结构,是不支持 二进制的一些命令的,而string类型则支持(setbit、getbit、bitcount…)
3、在redis集群中,要想将数据分布,不能用 hash 。在redis3.0的custer集群中, 是对key值做hash,然后取模,(是采用hash巢,基于key的crc16哈希函数的计算,然后跟哈洗巢进行取模,哈洗巢基于不同的硬件进行一个管理,)拿到一个位置的,当key一样的时候,位置一定是一样的,也就是说,一定是一个物理机上的,不能分布的存储。因为string类型的话,key是不同的,而hash类型的话,key是相同的,key中的field是不同的,但是集群的时候,是根据key来进行运算的,而不是根据field
总结
这里只是简单的介绍了一下redis的使用场景,以后会跟大家分享一下redis的底层原理与具体实现。