Redis五大数据结构

Redis五大数据结构


一、Redis五大数据结构

Redis有五大数据结构:string、list、hash、set和zset,在开发中使用频率很高,掌握了这五个数据结构基本上就掌握了Redis内容的一半了。本文主要对几种数据类型的基本操作以及使用场景进行归纳。

1.string

string表示的是一个可变的字节数组,Redis的字符串是动态字符数组,可以进行修改,内部结构实现上类似于Java的,采用预分配冗余空间的方式来减少内存的频繁分配。字符串实际分配的空间一般高于字符串长度,当字符串小于1M时,扩容时采用加倍现有的空间,超过1M,扩容时一次最多扩1M的空间。

(1).初始化字符串

set 变量名+变量内容

> set reader beijing.zhangyue.keji.gufen.youxian.gongsi
OK

(2).获取字符串的内容

get +变量名

> get reader
"beijing.zhangyue.keji.gufen.youxian.gongsi"

(3).获取字符串长度

strlen +变量名

> strlen reader
(integer) 42

(4).获取字串

getrange +变量名+开始位置+结束位置

> getrange reader 28 34
"youxian"

(5).覆盖字串

setrange +变量名称+开始位置+目标字串

> setrange reader 28 wooxian
(integer) 42  # 返回长度
> get ireader
"beijing.zhangyue.keji.gufen.wooxian.gongsi"

(6).追加字串

在字符串末尾添加

> append reader .hao
(integer) 46 # 返回长度
> get reader
"beijing.zhangyue.keji.gufen.wooxian.gongsi.hao"

:字符串没有提供字符插入方法和子串删除方法

(7).过期和删除

字符串可以使用del指令进行主动删除,使用expire指令设置过期时间,时间一过自动删除(被动删除),可以使用ttl指令获取字符串的寿命

> expire reader 60
(integer) 1  # 1表示设置成功,0表示变量reader不存在
> ttl reader
(integer) 50  # 还有50秒的寿命,返回-2表示变量不存在,-1表示没有设置过期时间
> del reader
(integer) 1  # 删除成功返回1
> get reader
(nil)  # 变量reader没有了

(8).计数

如果字符串的内容是整数,也可以当成计数来使用

> set reader 42
OK
> get reader
"42"
> incrby reader 100
(integer) 142
> get reader
"142"
> decrby reader 100
(integer) 42
> get ireader
"42"
> incr reader  # 等价于incrby reader 1
(integer) 43
> decr reader  # 等价于decrby reader 1
(integer) 42

(9).使用场景

1)缓存:

由于Redis具有支撑高并发的特性,通常能起到加速读写和减低后端压力的作用,web端的大多数请求都是从Redis中获取的数据,如果Redis中没有需要的数据,则会从MySQL中去获取,并将获取到的数据写入Redis

2) 计算:

Redis中有一个字符串相关的incr key,incr命令对值做自增操作,返回结果分为以下三种情况:
*值不是整数,返回错误
*值是整数,返回自增后的结果
*key不存在,默认键为0,返回1
文章的阅读量,视频的播放量等都会使用redis来计数,每播放一次,对应的播放量就会加1,同时将这些数据异步存储到数据库中达到持久化的目的。

3)共享Session:

在分布式系统中,用户的每一次请求都会访问到不同的服务器,这就会导致session不同步的问题,假如一个用来获取用户信息的请求落在A服务器上,获取到用户信息后存入session。下一个请求落在B服务器上,想要从session中获取用户信息就不能正常获取了,因为用户信息的session在服务器A上。使用Redis集中管理这些session,将session存入Redis,使用的时候直接从Redis中获取。

4)限速

为了安全考虑,有些网站会对IP进行限制,限制同一IP在一定时间内访问次数不能超过n次。

2.list

Redis列表的存储结构用的是双向链表,对列表进行首尾插入删除性能比较好,链表元素的位置使用自然数0,1,2,3,…,n-1表示,还可以使用负数-1,-2,…,-n来表示,-1表示倒数第一,-2表示倒数第二,-n表示第一个元素,对应的下标为0.

(1).从表头或者表尾追加或者移除元素

# 右进左出
> rpush reader go
(integer) 1
> rpush reader java python
(integer) 3
> lpop reader
"go"
> lpop reader
"java"
> lpop reader
"python"
# 左进右出
> lpush reader go java python
(integer) 3
> rpop reader
"go"
...
# 右进右出
> rpush reader go java python
(integer) 3
> rpop reader 
"python"
...
# 左进左出
> lpush reader go java python
(integer) 3
> lpop reader
"python"

(2).获取链表长度:llen+变量名

> rpush reader go java python
(integer) 3
> llen reader
(integer) 3

(3).随机读

lindex+变量名+位置来访问指定位置的元素;lrange+变量名+开始位置+结束位置来获取链表子元素列表;使用lrange获取全部元素时,需要提供end_index,如果没有负下标,需要通过llen获取长度,得到end_index,有负下标同样可以用-1替代。

> rpush reader go java python
(integer) 3
> lindex reader 1
"java"
> lrange reader 0 2
1) "go"
2) "java"
3) "python"
> lrange reader 0 -1  # -1表示倒数第一
1) "go"
2) "java"
3) "python"

(4).修改元素

lset+变量名+指定位置+修改值

> rpush reader go java python
(integer) 3
> lset reader 1 javascript
OK
> lrange reader 0 -1
1) "go"
2) "javascript"
3) "python"

(5).插入元素

linsert +变量名+before/after+指定位置(元素)+要插入的值

> rpush reader go java python
(integer) 3
> linsert reader before java ruby
(integer) 4
> lrange reader 0 -1
1) "go"
2) "ruby"
3) "java"
4) "python"

(6).删除元素

lrem+变量名+指定删除的最大个数+要删除的元素的值(可以是多个)

> rpush reader go java python
(integer) 3
> lrem reader 1 java
(integer) 1
> lrange reader 0 -1
1) "go"
2) "python"

(7).定长列表

ltrim+变量名+start+end,表示需要保留列表的下标范围,范围之外的所有元素都将会被移除,如果指定参数的end对应真实的下标小于start,其效果等价于del,因为这样的参数表示需要保留列表元素的下标范围为空。

> rpush reader go java python javascript ruby erlang rust cpp
(integer) 8
> ltrim reader -3 -1
OK
> lrange reader 0 -1
1) "erlang"
2) "rust"
3) "cpp"

(8).快速列表(压缩列表)

ziplist 经过特殊编码的双向列表结构,在列表元素较少的情况下会使用的一块连续的内存存储,数据量比较多的时候会改成quicklist。

(9).使用场景

1) .消息队列:

列表用来存储多个有序的字符串,满足消息队列的特点,使用lpush+rpop或者rpush+lpop实现消息队列。redis还支持阻塞操作,在弹出元素的时候使用阻塞命令来实现阻塞命令。

2).栈:

列表满足栈,那么也满足栈先进后出的特点。

3).文章列表:

列表支持索引范围获取元素,可以分页获取文章列表。

3.hash

等价于Java的HashMap,实现结构上使用二维结构,第一维是数组,第二维是链表,数组里存放的是链表的头指针,hash的内容key和value存放在链表中。通过key查找元素时,先计算key的hashcode,然后用hashcode对数组的长度进行取模定位到链表的表头,再对链表进行遍历获取到相应的value值。

(1).获取元素

hget定位具体key对应的value,hmget获取多个key对应的value,hgetall获取所有的键值对,hkey和hvals获取所有的列表和value值

> hmset reader go fast java fast python slow
OK
> hget reader go
"fast"
> hmget reader go python
1) "fast"
2) "slow"
> hgetall reader
1) "go"
2) "fast"
3) "java"
4) "fast"
5) "python"
6) "slow"
> hkeys reader
1) "go"
2) "java"
3) "python"
> hvals reader
1) "fast"
2) "fast"
3) "slow"

(2).删除元素

使用hdel删除指定的key,可以同时删除多个key

> hmset reader go fast java fast python slow
OK
> hdel reader go
(integer) 1
> hdel reader java python
(integer) 2

(3).判断元素是否存在

hexists指令

> hmset reader go fast java fast python slow
OK
> hexists reader go
(integer) 1

(4).扩容

采用渐进式rehash,同时保留两个新旧hash结构,申请新的两倍大下的数组,然后将所有的键值对重新分配到新的数组下标对应的链表中。

(5).缩容

与扩容原理一致,只不过新的数组大小要比旧数组小一倍。

(6).计数器

hash对于每一个内部的key都可以用作一个单独的计数器,如果value不是整数,调用会出错。

> hincrby reader go 1
(integer) 1
> hincrby reader python 4
(integer) 4
> hincrby reader java 4
(integer) 4
> hgetall reader
1) "go"
2) "1"
3) "python"
4) "4"
5) "java"
6) "4"
> hset reader rust good
(integer) 1
> hincrby reader rust 1
(error) ERR hash value is not an integer

(6).使用场景

存储、读取、修改用户属性

4.set

内部使用hash结构,所有的value指向同一个内部值。

(1).增加元素

一次可以增加多个元素

> sadd reader go java python
(integer) 3

(2).读取元素

使用smembers列出所有元素,使用scard获取集合长度,使用srandmembers获取随机count个元素,如果没有count参数,默认1.

> sadd reader go java python
(integer) 3
> smembers reader
1) "java"
2) "python"
3) "go"
> scard reader
(integer) 3
> srandmember reader
"java"

(3).删除元素

srem删除一到多个元素,spop删除随机一个元素

> sadd reader go java python rust erlang
(integer) 5
> srem reader go java
(integer) 2
> spop reader
"erlang"

(4).判断元素是否存在

sismember,接收单个元素

> sadd reader go java python rust erlang
(integer) 5
> sismember reader rust
(integer) 1
> sismember reader javascript
(integer) 0

(5).使用场景

抽奖功能:支持获取随机数;用户标签:将同一个特征相同的抽象为标签,例如一个用户对篮球、足球感兴趣,另一个用户对橄榄球、乒乓球感兴趣,这些兴趣点就是一个标签。有了这些数据就可以得到喜欢同一个标签的人,以及用户的共同感兴趣的标签。给用户打标签的时候需要①给用户打标签,②给标签加用户,需要给这两个操作增加事务。

5.zset

等价于Map<String,Double>,可以给每一个元素value赋予一个权重score;同时它类似于TreeSet,内部的元素会按照权重score进行排序,可以得到每个元素的名次,还可以通过score的范围来获取元素的列表。

(1).增加元素

zadd,增加一到多个score/value对

> zadd reader 4.0 python
(integer) 1
> zadd reader 4.0 java 1.0 go
(integer) 2

(2).获取长度

zcard得到元素个数

> zcard reader
(integer) 3

(3).删除元素

zrem删除元素,可以一次删除多个

> zrem reader go python
(integer) 2

(4).获取排名和分数

通过zscore获取自动元素的权重,zrank获取指定元素的正向排名,zrevrank获取指定元素的反向排名

> zscore reader python
"5"
> zrank reader go  # 分数低的排名考前,rank值小
(integer) 0
> zrank reader java
(integer) 1
> zrank reader python
(integer) 2
> zrevrank reader python
(integer) 0

(5).根据排名范围获取元素列表

zrange指定排名范围参数获取对应的列表,加withscores 可以获取元素的权重,zrevrange按负向排名获取元素列表

> zrange reader 0 -1  # 获取所有元素
1) "go"
2) "java"
3) "python"
> zrange reader 0 -1 withscores
1) "go"
2) "1"
3) "java"
4) "4"
5) "python"
6) "5"
> zrevrange reader 0 -1 withscores
1) "python"
2) "5"
3) "java"
4) "4"
5) "go"
6) "1"

(6).根据score范围获取列表

zrangebbyscore指定score范围获取对应的元素列表,zrevrangeyscore获取倒排元素列表,-inf表示负无穷,+inf表示正无穷

> zrangebyscore reader 0 5
1) "go"
2) "java"
3) "python"
> zrangebyscore reader -inf +inf withscores
1) "go"
2) "1"
3) "java"
4) "4"
5) "python"
6) "5"
> zrevrangebyscore reader +inf -inf withscores  # 注意正负反过来了
1) "python"
2) "5"
3) "java"
4) "4"
5) "go"
6) "1"

(7).根据范围移除元素列表

通过排名范围,也可以通过score范围来一次性移除多个元素

> zremrangebyrank reader 0 1
(integer) 2  # 删掉了2个元素
> zadd reader 4.0 java 1.0 go
(integer) 2
> zremrangebyscore reader -inf 4
(integer) 2
> zrange reader 0 -1
1) "python"

(8).使用场景

排行榜:例如用户发表文章,用score来表示点赞量,根据点赞量进行排行;延迟消息队列,例如下单系统,下单后需要在15分钟内支付,如果15分钟内未支付,则订单取消,下单后的15分钟时间作为score,订单作为value存入redis,如果消费的时间大于这笔记录的score,则将这笔记录移除订单。

总结

以上就是Redis五大数据结构以及相关用法和使用场景

  • 7
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值