


用好这五种数据类型将给你的开发带来很大的便利,给你的程序带来很大的性能提高,同时这五种数据类型能玩出不少花样。javascript
其实这个问题也是面试中问到Redis时的一个“开篇词”,问这个问题主要有两个缘由:css
第一,看看你到底有没有全面的了解Redis有哪些功能,通常怎么来用,什么场景用什么数据类型,就怕你只会最简单的kv操做java
第二,看看你在实际项目里都怎么玩儿过Redis,经验是否丰富android
要是你回答的很差,没说出几种数据类型,也没说什么场景,你完了,面试官对你印象确定很差,以为你平时就是作个简单的set和get,没思考过。nginx
废话很少说,进入正题吧。Redis一共提供了5种数据类型,分别是String,Hash,List,Set,sorted set(Zset),下面就从各个数据类型的基本经常使用命令和使用场景分别说说吧。web
String字符串结构的经常使用命令面试
#字符串经常使用操做SET key value //存入字符串键值对MSET key value [key value ...] //批量存储字符串键值对SETNX key value //存入一个不存在的字符串键值对GET key //获取一个字符串键值MGET key [key ...] //批量获取字符串键值DEL key [key ...] //删除一个键EXPIRE key seconds //设置一个键的过时时间(秒)#原子加减INCR key //将key中储存的数字值加1DECR key //将key中储存的数字值减1INCRBY key increment //将key所储存的值加上incrementDECRBY key decrement //将key所储存的值减去decrement
这里列出了一些String经常使用命令,咱们看一下这些String类型的这些命令能够应用到哪些场景。redis
应用场景spring
一、单值缓存sql
即最简单的key-value的set和get,好比缓存个标识,开关等
SET key valueGET key
二、对象缓存
除了单值缓存咱们还能够用String类型缓存对象,以下两种方式:
#1SET user:1 value(json串)GET user:1#2MSET user:1:name 编程大道 user:1:sex 1MGET user:1:name user:1:sex
第一种直接将对象转换成json串做为value存储到redis,这种获取对象就比较简单了,直接get key拿到value转成对象便可,但有个缺点就是若是你要是修改对象的某一个字段,也得把整个对象的json串拿出来反序列化成对象,这将带来没必要要的网络开销(即使是redis存在内存中,但实际咱们的应用服务器和redis是隔离的,网络传输的开销也不容小觑),一样,频繁的序列化反序列化也将会带来不小的性能开销,若是对于性能要求比较高的系统来讲这将是一个灾难。
而第二种存储对象的方式则对于这种频繁修改对象某一个字段的场景就比较友好了,每一个字段与值都是一个kv对,修改直接set k v覆盖就行了,可是存储多个字段时就没那么容易了,好在有mset批量操做的命令,网络开销由屡次变为1次。
三、分布式锁
以下setnx命令是set if not exit的缩写,意思就是这个key不存在时才执行set。多个线程执行这条命令时只有一个线程会执行成功,则视为拿到锁。而后拿到锁的线程执行业务操做,执行完毕删除这个锁,释放锁。
#setnx key valueSETNX product:10001 true //返回1表明获取锁成功SETNX product:10001 true //返回0表明获取锁失败//执行业务操做DEL product:10001 //执行完业务释放锁
上述方式存在问题:程序意外终止可能会致使锁没办法释放,形成死锁。可使用以下命令,既设置分布式锁又设置了key的过时时间
SET product:10001 true ex 10 nx //防止程序意外终止致使死锁
分Redis布式锁的详细实现能够参考我以前写的Redis分布式锁实战
四、计数器
INCR article:readcount:{文章id}GET article:readcount:{文章id}
基于Redis原子自增命令incr能够实现诸如计数器的功能,咱们都知道公众号文章,微博,博客都有一个阅读量的概念,咱们就能够用这个计数器来实现,并且性能很高。
例以下图中的阅读数就能够用redis的自增来实现
五、Web集群session共享解决方案
系统集群部署状况下首先要考虑的问题就是session共享问题,咱们能够经过将本来存储在内存中由tomcat管理的session转移到由Redis来存储,实现分布式session的功能。spring框架提供了session共享的解决方案,即spring session + redis实现分布式session。
六、分布式系统全局序列号
分布式系统中要保证全局序列号的惟一性,可使用Redis来维护一个自增的序列。
经过以下命令从Redis获取自增ID:
INCR orderId//INCR是一个原子自增命令
分布式系统环境下经过Redis保证ID的自增性和惟一性,经过该命令获取ID每次都要和Redis进行交互,若是业务量很大,那么这将会很频繁。
因此能够一次性获取必定量的ID保存在JVM内存中,用完了再从Redis获取。这样减小了频繁的网络开销,可是缺点是可能会丢失(浪费)一部分ID,由于获取后服务可能挂了还没用完的ID可能就浪费了(固然你可使用一些手段去保证不浪费,但不必,浪费一点也是无所谓的)。
以下,每次获取1000个
INCRBY orderId 1000//redis批量生成序列号提高性能
Hash经常使用操做
HSET key field value//存储一个哈希表key的键值HSETNX key field value//存储一个不存在的哈希表key的键值HMSET key field value [field value ...] //在一个哈希表key中存储多个键值对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
应用场景
一、对象缓存
结合HASH结构的key-field-value的特性,相似于Java中的HashMap,内部也是“key-value”的形式,field恰好能够存对象的属性名,假设有以下数据,
咱们能够用HMSET命令批量设置field-value,前面拼接用户的ID保证存多个用户的数据不会重复;HMGET批量获取field;MSET修改某一个field。
HMSET achievement {userId}:name 小明 {userId}:score 89HMSET achievement 1:name 小明 1:score 89HMSET achievement 2:name 小华 2:score 92HMGET achievement 1:name 1:score
对象与HSAH的关系就变成了下图这样
二、电商购物车
以用户id为key,商品id为field,商品数量为value能够实现购物车的常规操做。
购物车操做:
#添加商品hset cart:10001 50005 1#给某一个商品增长数量hincrby cart:10001 50005 1#购物车中商品总个数hlen cart:10001#删除商品hdel cart:10001 50005#获取购物车全部商品hgetall cart:10001
对应购物车的几个经常使用操做能够想象使用Redis如何实现
Hash结构优缺点
优势
将同类数据归类整合储存(同一个key),方便数据管理
相比String操做,对内存与cpu的消耗更小
相比String储存更节省空间
缺点
过时功能不能使用在field上,只能用在key上
Redis集群架构下不适合大规模使用
List经常使用操做
咱们能够认为列表的左边叫头,右边叫尾
List结构的操做示意图
经常使用命令
LPUSH key value [value ...] //将一个或多个值value插入到key列表的表头(最左边)RPUSH key value [value ...]//将一个或多个值value插入到key列表的表尾(最右边)LPOP key//移除并返回key列表的头元素RPOP key//移除并返回key列表的尾元素LRANGE key start stop//返回列表key中指定区间内的元素,区间以偏移量start和stop指定
BLPOP key [key ...] timeout//从key列表表头弹出一个元素,若列表中没有元素,阻塞等待timeout秒,若是timeout=0,一直阻塞等待BRPOP key [key ...] timeout //从key列表表尾弹出一个元素,若列表中没有元素,阻塞等待timeout秒,若是timeout=0,一直阻塞等待LLEN key //list的长度
应用场景
一、实现常见的数据结构
基于List的特性及丰富的命令能够实现经常使用的集中数据结构:
1)Stack(栈) = LPUSH + LPOP ,FILO先入后出
结合LPUSH和LPOP命令实现栈的先进后出的特性,LPUSH从左边入栈,LPOP从左边出栈,先进入的后出来。至关于入口出口是一个。
2)Queue(队列)= LPUSH + RPOP,FIFO先进先出
结合LPUSH和RPOP命令实现队列的先进先出的特性,LPUSH从左边入队,RPOP从右边出队,先进来的先出来。至关于入口出口各在两边。
3)Blocking MQ(阻塞队列)= LPUSH + BRPOP
结合LPUSH和BRPOP实现阻塞队列,BRPOP比RPOP多了一个timeout的参数,是一个等待的最大时间,若是在这个时间内拿不到数据则返回空。
二、微博消息和微信公号消息
例如,walking本人关注了人民网、华为中国、京港地铁等大V,假设人民网发了一条微博,ID为30033,我关注了他,那么就会往个人msg这个队列里push这个微博ID,我在打开个人微博时,就会从这个我专属的msg队列里取前几个微博ID展现给我看,因此这个就牵涉到了几个关键点:
1)人民网发了一条微博,ID为30033,消息ID入队
LPUSH msg:{walking-ID} 30033
2)华为中国发微博,ID为30055,消息入队
LPUSH msg:{walking-ID} 30055
3)我登陆进去,会给我展现最新微博消息,那么就从个人消息队列里取最新的前5条显示在首页
LRANGE msg:{walking-ID} 0 5
Set经常使用操做
SADD key member [member ...]//往集合key中存入元素,元素存在则忽略,若key不存在则新建SREM key member [member ...]//从集合key中删除元素SMEMBERS key //获取集合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中
应用场景
一、微信抽奖小程序
想必你们都用过微信里的抽奖小程序吧,以下图,咱们能够点击当即参与进行抽奖,还能够查看全部参与人员,最后就是开奖的功能,一共三个关键点
咱们看一下这三个关键点用set数据类型怎么实现:
1)点击参与抽奖,则将用户ID加入集合
SADD key {userlD}
2)查看参与抽奖全部用户
SMEMBERS key
3)抽取count名中奖者
SRANDMEMBER key [count]//返回但不从set中剔除SPOP key [count]//返回并剔除
若是设置了一等奖二等奖三等奖...,而且每人只能得一种,则能够用SPOP key count
二、微信微博点赞,收藏,标签
好比walking发了一条朋友圈,有人点赞
1) 点赞 点赞就把点赞这我的的ID加到这个点赞的集合中
SADD like:{消息ID} {用户ID}
2) 取消点赞 从集合中移除用户ID
SREM like:{消息ID} {用户ID}
3) 检查用户是否点过赞
SISMEMBER like:{消息ID} {用户ID}
4) 获取点赞的用户列表
SMEMBERS like:{消息ID}
5) 获取点赞用户数
SCARD like:{消息ID}
Set集合运算操做的应用场景
基于Redisset集合提供的丰富的命令,咱们能够对集合轻松的实现交并差的运算。例如,现有集合set1,set12,set3,元素以下:
set1:{a,b,c}set2:{a,c,e}set3:{c,d,f}
对集合进行交、并、差的运算
SINTER set1 set2 set3 //交集--> { c } SUNION set1 set2 set3 //并集--> { a,b,c,d,e,f } SDIFF set1 set2 set3 //差集--> { b }
三、集合操做实现社交软件关注模型
社交软件的用户关注模型,如QQ的好友,微博的关注,抖音、快手的关注、微信的公众号关注,这些社交软件都会作一个这样的功能,那就是用户关系的关注模型推荐,包括共同关注的人、可能认识的人、
首先看一下walking、chenmowanger、Hollis关注的人,以下:
1)walking关注的人:
walkingSet-->{chenmowanger, ImportNew, Hollis}
2) chenmowanger关注的人:
chenmowangerSet-->{walking, ImportNew, Hollis, JavaGuide}
3) Hollis关注的人:
HollisSet--> {waking, ImportNew, JavaGuide, feichao, CodeSheep}
(开玩笑,大佬们才没关注我,哈哈😂)
每一个人的关注列表都是一个Redis的set集合,而后当walking点到chenmowanger的主页,就会有个区域专门展现我和二哥的一些关注状况:
4) walking和chenmowanger共同关注:
也就是看哪些人在个人集合里也在二哥的集合里
//两个集合求并集SINTER walkingSet zhangyixingSet--> {ImportNew, Hollis}
5) 我关注的人也关注他(chenmowanger):
看我关注的人的关注列表里是否是有某我的,好比我进入chenmowanger的主页,能够展现我关注的人里还有谁也关注了chenmowanger
SISMEMBER ImportNewSet chenmowangerSISMEMBER HollisSet chenmowanger
6) 我可能认识的人:
求差集,之前面这个集合为准,看二哥关注的那些人有哪些我还没关注,因而我就赶忙关注了JavaGuide(Guide哥)
SDIFF chenmowangerSet walkingSet->{walking, JavaGuide}
四、集合操做实现电商商品筛选
先看一下这个图是否是很熟悉,选购手机时,有一个筛选的功能
如上图,电商网站买手机,进到这个页面根据各类条件搜手机,咱们想想用Redis如何实现呢?(固然了,这里并非说人家就彻底用Redis实现这一套搜索,其实主要仍是用搜索引擎那些中间件,这里只是说明能够用Redis实现~)
在上架商品时维护商品,添加商品的同时把对应的商品添加到对应的set集合里便可,以下举例
//品牌-华为SADD brand:huawei P30 Mate30 荣耀Play4 nova7//品牌-小米SADD brand:xiaomi mi6 mi8 mi9 mi10//品牌-iPhoneSADD brand:iPhone iphone8 iphone8plus iphoneX iphone11//操做系统-AndroidSADD os:android P30 Mate30 荣耀Play4 nova7 mi6 mi8 mi9 mi10//CPU品牌-骁龙SADD cpu:brand:xiaolong iphone8 iphone8plus iphoneX iphone11 mi6 mi8 mi9 mi10//CPU品牌-麒麟SADD cpu:brand:qilin P30 Mate30 荣耀Play4 nova7//运行内存-8GSADD ram:8G P30 Mate30 荣耀Play4 nova7 mi6 mi8 mi9 mi10 iphone8 iphone8plus iphoneX iphone11//多条件查询 操做系统Android,CPU品牌骁龙,运行内存8GSINTER os:android cpu:brand:xiaolong ram:8G -->{mi6 mi8 mi9 mi10}
截图更容易看:
假设咱们维护了各类品牌,手机所属的操做系统,CPU品牌,运行内存等,那么咱们在勾选条件查找时就能够用勾选的各个集合求他的交集就好了。
zset是有序的set集合,经过传入的分值进行排序
ZSet经常使用操做
ZADD key score member [[score member]…]//往有序集合key中加入带分值元素ZREM key member [member …] //从有序集合key中删除元素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 …]//交集计算
应用场景
一、Zset集合操做实现排行榜
咱们都知道微博热点,新闻热榜,投票排行榜等都有一个排名的概念,以下图百度热榜,展现的是实时的点击量比较高的新闻(假设这些新闻的ID为1001-1010),每一个新闻都有一个热点值,通常按点击量,1001这个新闻热点是484W,1002这个是467W,实时的,可能等会再看就不同了,那么咱们看下用Redis咋实现。
1)点击新闻
每次有人点击这个新闻,那么久ius给他的分值加1
ZINCRBY hotNews:20200722 1 1001 //新闻ID为1001的新闻分值加一
2)展现当日排行前十
取集合中的前10个元素
ZREVRANGE hotNews:20200722 0 10 WITHSCORES
3)七日热点榜单计算
ZUNIONSTORE hotNews:20200715-20200721 7 hotNews:20200715 hotNews:20200716... hotNews:20200721
4)展现七日排行前十
ZREVRANGE hotNews:20190813-20190819 0 10 WITHSCORES
微信<摇一摇><抢红包>
滴滴打车、摩拜单车<附近的车>
美团和饿了么<附近的餐馆>
搜索自动补全
布隆过滤器
别走开,有彩蛋 ↓ ↓ ↓

本文分享自微信公众号 - 编程大道(learn_code)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。