提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录- 前言
- 一、redis的8种数据类型?
- 1、string类型
- 2、hash类型
- 3、list类型
- 4、set类型
- 5、zset类型的命令
- 6、geospatial & hyperloglog & Bitmap
- 二、使用场景
- 1、string类型
- 2、hash类型
- 3、list类型
- 4、set类型
- 5、zset类型
- 三、其他
- 1、hash 比 string 的优点?
- 2、string 比 hash 的优点?
- 总结
前言
今天来介绍一下,redis的各个数据结构以及他们的使用场景。本人水平有限,如有误导,欢迎斧正,一起学习,共同进步!
一、redis的8种数据类型?
redis中一共有8种数据类型,有5种基本数据类型和3种特殊数据类型
基本数据类型:String、List(集合)、Set(集合)、ZSet(有序集合)、Hash(哈希)
特殊数据类型:geospatial(地理位置)、hyperloglog(优点:占用内存小)、Bitmap(位图)
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 num2、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 13、list类型
-
可以实现消息的队列。因为他有一个命令叫做 blpop key timeout。阻塞的等待timeout秒。可以用provider往队列中插入消息,consumer阻塞的从队列中消费消息,虽然不像专门的消息队列那样,有顺序性、持久性的解决方案,但是也能实现这个功能(需要从别的地方限制)
-
可以实现,关注的列表的最新的消息。比如说,你关注的人有张三、李四,俩人。那你 2021.8.3 看的时候,应该是推送的 2021.8.3 的内容;你 2021.8.4 看的时候,应该推送的就是 2021.8.4 的消息了。那么怎么实现,最新的消息,放在最前面呢?可以用redis的 rpush key v 来实现,往最前面推送最新的消息。
- 比如说是抽奖。微博有博主说,你转发我的微博,我随机抽奖。(或者是刷礼物抽奖什么的),比如说,谁转发了你的微博,你就 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、可以将信息凝聚在一起,便于管理
2、从一定程度上可以避免误操作,减少key冲突
3、减少内存/io/cpu 的消耗(这点是说,redis是针对于key的扫描,检索,ttl过期之类的都是针对于这个key的,虽然这个key里面有多个field,但是还是只有一个key。若是使用字符串的话,要想达成同样的目的,则会产生大量的key,会产生大量的key的一个扫描,而使用一个key的话,会减少最外层的key的,cpu的消耗。比如说key是冲突啊,对key的管理啊什么的,一个key所消耗的资源肯定比多个key所消耗的资源少)
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的底层原理与具体实现。



