【Redis】五种数据结构的常用命令,及多种应用场景示例

 

Redis 是一个开源,高级的键值存储和一个适用的解决方案,用于构建高性能,可扩展的 Web 应用程序。Redis 也被作者戏称为数据结构服务器 ,这意味着使用者可以通过一些命令,基于带有 TCP 套接字的简单 服务器-客户端 协议来访问一组可变数据结构 。(在 Redis 中都采用键值对的方式,只不过对应的数据结构不一样罢了)。

Redis 有 5 种基础数据结构,它们分别是:string(字符串)、list(列表)、hash(字典)、set(集合) 和 zset(有序集合)。这 5 种是 Redis 相关知识中最基础、最重要的部分,下面我们说一下它们基本的操作命令和应用场景。

【Redis】五种数据结构的常用命令,及多种应用场景示例
进入redis客户端:

redis-cli -a -c -h -p            // -a访问服务端密码,-c表示集群模式,-h指定主机ip,指定端口号)
redis-cli 						 // 本机6379 无密码 单体模式
redis-cli -a 123456 -p 6374 -c   // 本机6374 密码123456 集群模式

1.String

字符串 string 是Redis 最简单的数据结构。Redis 所有的数据结构都是以唯一的 key 字符串作为名称,然后通过这个唯一 key 值来获取相应的 value 数据。

1.1 常用命令

1.增(set)

set key value 						// 存入字符串键值对
mset key value [key value...] 	    // 批量存储字符串键值对
setnx key value 					// 存入一个不存在的键值对(只有当前key不存在时才能增加成功)

2.删除与过期

del key [key...]					// 删除一个键
expire key seconds 				    // 设置过期时间(秒)

3.原子操作

incr key 							 // 将key中存储的数字加1
incrby key increment 				 // 将key锁存储的值加上increment

decr key							 // 将key中存储的数字减1
decr key decrement                   // 将key所存储的值减去decrement

4.查(get)

get key                               // 获取一个字符串的键值
mget key [key...]					  // 批量获取字符串键值

1.2 应用示例

1.对象缓存

  • 方式一:利用set命令,一次将对象的json字符串存入
set user:1 value(对象的json字符串)
  •  
  • 方式二:利用mset将对象的各个字段分开存储。这种方案更加灵活,可以对指定字段进行操作
mset user:1:name zhangsan user:1:age 18
mget user:1:name ~~ user:1:age ~~

2.简单分布式锁

通过setnx只能新增不存在的可以进行简单的分布式锁

PS:分布式锁问题就是放大版的单机线程同步问题,这不过这里不再是一个个线程,而是一台*立的服务器(进程)。

setnx product true 			// 进程一设置成功 == 获取到锁
setnx product true 			// 进程二再来时设置失败 == 阻塞

......						// 操作临界资源

del product 				// 进程一释放锁

注意:一般最好设置过期时间来避免死锁

set product true ex 10 nx 	// 过期时间=10s

3.计数器
【Redis】五种数据结构的常用命令,及多种应用场景示例

incr article:readcount:{文章id}
get article:readcount:{文章id}

4.Web集群Session共享

spring session + redis 实现session共享

2.Hash(哈希表)

Redis 的字典相当于Java 语言里面的 HashMap,它是无序字典。内部实现结构上同 Java 的 HashMap 也是一致的,同样的数组 + 链表二维结构。第一维 hash 的数组位置碰撞时,就会将碰撞的元素使用链表串接起来。

优点:

  • 同类数据归类整合存储,方便数据管理
  • 相比string操作消耗内存与cpu更小
  • 相比string更节省空间

缺点:

  • 过期功能不能用在field上,只能用在key上
  • Redis集群架构下不适合大规模使用

2.1 常用命令

1.增(hset)

hset key filed value                              // 存储一个哈希表key的剑指

hmset key filed value [filed value...]      	  // 在一个哈希表key中存储多个键值对
hsetnx key filed value                            // 存储一个不在的哈希表key的键值

2.删

hdel key filed [key filed...]                     // 删除哈希表key中的field键值

3.原子操作

hincrby key filed increment  					   // 为哈希表key中field键的值加上增量increment

4.查(hget)

hget key filed                                     // 获取哈希表key对应的field键值
hmget key filed [key filed...]    				   // 批量获取哈希表key中多个field键值
hlen key                    				       // 返回哈希表key中field的数量
hgetall key 									   // 返回哈希表中所有的键值

2.2 应用示例

1.对象缓存

用hash结构存储对象相较于string:cpu占用小,而且更节省空间

hmset user:1 name zhangsan age 18 
hmget user:1 name age

2.模拟购物车(字段修改)

以用户id为key,商品id为field,商品数量为value
【Redis】五种数据结构的常用命令,及多种应用场景示例

hset cart:1001 10088 1    				// 添加商品
hincrby cart:1001 10088 1			    // 增加数量
hlen cart:1001						    // 商品总数
hdel cart:1001							// 删除商品
hgetall cart:1001						// 获取购物车所有商品

3.List(队列&栈)

Redis 的列表相当于 Java 语言里面的 LinkedList,注意它是链表而不是数组。这意味着 list 的插入和删除操作非常快,时间复杂度为 O(1),但是索引定位很慢,时间复杂度为 O(n),这点让人非常意外。 当列表弹出了最后一个元素之后,该数据结构自动被删除,内存被回收

3.1 常用命令

【Redis】五种数据结构的常用命令,及多种应用场景示例

1.存(push)

lpush key value [key value...]			// 将一个或多个值value插入到key列表的表头(最左边)
rpush key value [key value...]			// 将一个或多个值value插入到key列表的表尾(最右边)

2.取(pop)

lpop key								// 移除并返回key列表的头元素
rpop key								// 溢出并返回key列表的尾元素

blpop key timeout					    // 从key列表表头弹出一个元素,若列表中没有元素,阻塞等待timeout秒,如果timeout=0,一直阻塞等待
brpop key timeout					    // 从key列表表尾弹出一个元素,若列表中没有元素,阻塞等待timeout秒,如果timeout=0,一直阻塞等待

lrange key start stop 					// 范围取(range),返回列表key中指定区间[start,stop]内的元素,

3.2 应用示例

1.实现栈,队列,阻塞队列

一般都使用lpush,pop看具体场景要求

stack(栈) = lpush + lpop // FILO
 
queue(队列) = lpush + rpop // FIFO

blockingqueue(阻塞队列) = lpush + brpop

2.订阅(消息队列)

list可以用于微博和微信的订阅消息,比如我关注了某个公众号,它一发文章我就能收到

  1. 服务器通过redis为每个用户都维护一个消息队列
  2. 当某个用户发送消息后,通过查数据库查出订阅者的uId,然后向指定消息队发送
  3. 待订阅者打开相关页面时,再从相应消息队列里取出
//...消息发送方查出订阅者uId

// 向订阅者的通道发送消息
lpush msg:uId msgId1
lpush msg:uId msgId2

// 从队列中取出消息给订阅者
lrange msg:uId 0 5 // 取5条msg

4.Set(随机队列)

Redis 的集合相当于 Java 语言里面的 HashSet,它内部的键值对是无序的唯一的。它的内部实现相当于一个特殊的字典,字典中所有的 value 都是一个值NULL。 当集合中最后一个元素移除之后,数据结构自动删除,内存被回收

4.1 常用命令

1.存(sadd)

sadd key member [member...]				// 向集合中存入元素,元素存在则忽略,key不存在则新建

2 取(srandmember&spop)

srandmember key [count] 				// 随机取count个元素,不删除
spop key [count]					    // 随机取count个元素,删除

3.查 & 删

smembers key							 // 获取集合key中所有元素
scard key								 // 获取集合key的元素个数
smember key member 						 // 判断元素member是否在集合key中

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

4.集合操作

sinter key [key...] 					 // 多个key的Set 取交集
sunion key [key...]				         // 并集
sdiff key [key...]						 // 差集

【Redis】五种数据结构的常用命令,及多种应用场景示例

4.2 应用示例

1.微信抽奖小程序(随机出队)

【Redis】五种数据结构的常用命令,及多种应用场景示例

将参与抽奖的user放入set,可以查看抽奖人数,然后随机抽取count个(srandmember),并决定是否删除中奖用户。

sadd key {userId}			    // 将参与抽奖用户放入集合。
smembers act:1			 		// 查看所有参与抽奖用户
srandmemeber key [count]        // 抽取count名中奖者(不删除中奖人)
spop key [count] 				// 抽取count名中奖者(删除中奖人)

2.点赞(不可重复性)

将点赞的人放入set,可以判断该用户是否点过赞

sadd like:{消息ID} {用户ID}		 //	点赞
srem like:{消息ID} {用户ID}		 // 取消点赞
sismember like:{消息ID} {用户ID}	 // 检查用户是否点过赞
smembers like:{消息ID} 			 // 获取点赞用户列表
scard like:{消息ID} 				 // 获取点赞用户数

3.微信微博关注模型(集合运算)

通过set的集合运算可以得到,用户间互相关注的都有谁

sinter love:uId1 love:uId2 		 // 得到user1与user2的共同关注(交集)

4.实现电商商品筛选
【Redis】五种数据结构的常用命令,及多种应用场景示例

sadd brand:huawei P30
sadd brand:xiaomi mi-6X
sadd brand:iphone iphone8
sadd os:android P30 mi-6X
sadd cpu:brand:intel P30 mi-6X
sadd ram:8G P30 mi-6X iphone8

sinter os:android cpu:brand:intel ram:8G ==> {P30, mi-6X}

5.ZSet(有序列表)

zset 似于 Java 的 SortedSet 和 HashMap 的结合体,一方面它是一个 set,保证了内部 value 的唯一性,另一方面它可以给每个 value 赋予一个 score,代表这个 value 的排序权重。

【Redis】五种数据结构的常用命令,及多种应用场景示例

5.1 常用命令

ZADD key score member [[score member]…]		// 往有序集合key中加入带分值元素
ZCARD key									// 返回有序集合key中元素个数
ZREM key member [member …]					// 从有序集合key中删除元素

ZINCRBY key increment member				// 为有序集合key中元素member的分值加上increment 
ZSCORE key member 							// 返回有序集合key中元素member的分值
ZRANGE key start stop [WITHSCORE] 		    // 正序获取有序集合key从start下标到stop下标的元素(withscores 参数可以附带获取元素的 score)
ZREVRANGE key start stop [WITHSCORE]		// 倒序获取有序集合key从start下标到stop下标的元素(withscores 参数可以附带获取元素的 score)

ZUNIONSTORE destkey numkeys key [key ...] 	// 并集计算,deskey(合并后的结果集、无重复),numkeys(要合并的集合的个数),key(要合并的集合)
ZINTERSTORE destkey numkeys key [key …]		// 交集计算

5.2 应用示例

1.实现排行榜

【Redis】五种数据结构的常用命令,及多种应用场景示例

ZINCRBY  hotNews:20201104  这就是开放不止步的中国   						// 点击新闻,当前新闻score+1

ZREVRANGE  hotNews:20201104  0  10  									// 展示当日排行前十

ZUNIONSTORE  hotNews:week 7 hotNews:20201104 ... hotNews:20201110   	// 合并七日的结果到 hotNews 这个Set中
ZREVRANGE   hotNews:week 0 7				 							// 在 hotNews 中取七日搜索榜单前七个

2.其余功能

ZSet 还可以用来存粉丝列表,value 值是粉丝的用户 ID,score是关注时间。我们可以对粉丝列表按关注时间进行排序。

ZSet 也可以用来存储学生的成绩,value 值是学生的 ID,score是他的考试成绩。我们可以对成绩按分数进行排序就可以得到他的名次。

上一篇:Procedure V2介绍


下一篇:Linux内核中container_of宏的详细解释