Redis基本数据类型


前言

基本数据结构包含:字符串(string)、 散列(hash)、 列表(list)、 集合(set)、 有序集合(zset)五种。这五种数据结构在我们工作中经常使用到,面试过程中经常被问到,因此熟练掌握这5种基本数据结构的使用和应用场景是Redis知识最基础也是最重要的部分。


一、字符串类型(string)

字符串是Redis最简单的存储类型,它存储的值可以是字符串、整数、或者浮点数,对整个字符串或者字符串的其中一部分执行操作;对整数或浮点数执行自增(increment)或者自减(decrement)操作。
键值对
Redis的字符串是一个由字节组成的序列,跟java里面的ArrayList有点类似,采用预分配冗余空间的方式来减少内存的频繁分配,如图中所示,内部为当前字符串实际分配的空间 capacity 一般要高于实际字符串长度 len。当字符串长度小于 1M 时,扩容都是加倍现有的空间,如果超过 1M,扩容时一次只会多扩 1M 的空间。需要注意的是字符串最大长度为 512M
在这里插入图片描述
应用场景

字符串类型在工作中使用广泛,主要用于缓存数据,提高查询性能。比如存储登录用户信息、电商中存储商品信息、可以做计数器(想知道什么时候封锁一个IP地址(访问超过几次))等等。

操作指令
在这里插入图片描述

set key value  						添加一条String类型的数据
get key  							获取一条String类型的数据
mset key1 value1 key2 value2  		添加多条String类型数据
mget key1 key2  					获取多条String类型数据
incr key							自增(默认步长1)
incrby key step   					按照步长自增
decr key							自减(默认步长1)
decrby key step						按照步长自减

实践

#插入字符串
>set username zs
"OK"

#获取字符串
>get username
"zs"

#插入多个字符串
>mset username lisi age 18
"OK"

#获取多个字符串
>mget username age
"lisi"
"18"

#自增
>incr num
1
>incr num
2

#自减
>decr num
1
>decr num
0

#指定步长自增
>incrby num 2
2
>incrby num 2
4

#指定步长自减
>decrby num 3
1

#删除
>del num
"1"

二、散列(hash)

散列相当于Java中的HashMap,内部是无序字典。实现原理跟HashMap一致。一个哈希表有多个节点,每个节点保存一个键值对。

在这里插入图片描述
与Java中的HashMap不同的是,rehash 的方式不一样,因为 Java 的 HashMap 在字典很大时,rehash 是个耗时的操作,需要一次性全部 rehash。Redis 为了高性能,不能堵塞服务,所以采用了渐进式 rehash 策略。

在这里插入图片描述
渐进式 rehash 会在 rehash 的同时,保留新旧两个 hash 结构,查询时会同时查询两个 hash 结构,然后在后续的定时任务中以及 hash 操作指令中,循序渐进地将旧 hash 的内容一点点迁移到新的 hash 结构中。当搬迁完成了,就会使用新的hash结构取而代之。

当 hash 移除了最后一个元素之后,该数据结构自动被删除,内存被回收。

应用场景

Hash也可以同于对象存储,比如存储用户信息,与字符串不一样的是,字符串是需要将对象进行序列化(比如json序列化)之后才能保存,而Hash则可以讲用户对象的每个字段单独存储,这样就能节省序列化和反序列的时间。如下:

在这里插入图片描述
此外还可以保存用户的购买记录,比如key为用户id,field为商品id,value为商品数量。同样还可以用于购物车数据的存储,比如key为用户id,field为商品id,value为购买数量等等。

操作指令
在这里插入图片描述

# 设置属性
hset keyname field1 value1 field2 value2
# 获取某个属性值
hget keyname field
# 获取所有属性值
hgetall keyname
# 删除某个属性
hdel keyname field
# 获取属性个数
hlen keyname
# 按照步长自增/自减某个属性(该属性必须是数字)
hincrby keyname field step

实践

# 插入 hash 数据
>hset userInfo username zhangsan age 18 address bj
"3"
# 获取 hash 单条 field 数据
>hget userInfo username
"zhangsan"
>hget userInfo age
"18"
# 获取 hash 多个 field 数据
>hmget userInfo username age
1) "zhangsan"
2) "18"
# 获取 hash 所有 field 数据
>hgetall userInfo
1) "username"
2) "zhangsan"
3) "age"
4) "18"
5) "address"
6) "bj"
# 获取 hash 的 field 个数
>hlen userInfo
"3"
# 自增 hash 的某个 field
>hincrby userInfo age 2
"20"
>hincrby userInfo age 2
"22"
# 自减 hahs 的某个 field(通过自增负步长达到)
>hincrby userInfo age -2
"20"
# 删除 hash 的某个 field
>hdel userInfo age
"1"
# 删除 hash 所有数据
>del userInfo
"1"

三、列表(list)

Redis中的lists相当于Java中的LinkedList,实现原理是一个双向链表(其底层是一个快速列表),即可以支持反向查找和遍历,更方便操作。插入和删除操作非常快,时间复杂度为 O(1),但是索引定位很慢,时间复杂度为 O(n)。

应用场景

lists的应用场景非常多,可以利用它轻松实现热销榜;可以实现工作队列(利用lists的push操作,将任务存在lists中,然后工作线程再用pop操作将任务取出进行执行 );可以实现最新列表,比如最新评论等。

操作指令
在这里插入图片描述

# 左进
lpush key value1 value2 value3...
# 左出
lpop key
# 右进
rpush key value1 value2 value3...
# 右出
rpop key
# 从左往右读取 start和end是下标
lrange key start end

实操

# 从 list 左边依次插入
>lpush student zhangsan lisi wangwu
"3"
# 从 list 右边插入
>rpush student tianqi
"4"
# 从 list 左边弹出一个
>lpop liangshan
"wangwu"
# 从 list 右边弹出一个
>rpop liangshan
"tianqi"
# 获取 list 下标 0 ~ 1 的数据(左闭右闭)
>lrange liangshan 0 1
 1) "lisi"
 2) "zhangsan"

注意:blpop 阻塞版获取

为什么要阻塞版本的pop呢,主要是为了避免轮询。举个简单的例子如果我们用list来实现一个工作队列。执行任务的thread可以调用阻塞版本的pop去获取任务这样就可以避免轮询去检查是否有任务存在。当任务来时候工作线程可以立即返回,也可以避免轮询带来的延迟.

四、集合(set)

集合类似Java中的HashSet,内部实现是一个value永远为null的HashMap,实际就是通过计算hash的方式来快速排重的,这也是set能提供一个成员是否在集合内的原因。

应用场景

redis的set类型是使用哈希表构造的,因此复杂度是O(1), 它支持集合内的增删改查,并且支持多个集合间的交集、并集、差集操作。可以利用这些集合操作,解决程序开发过程当中很多数据集合间的问题。比如计算网站独立ip,用户画像中的用户标签,共同好友等功能

操作指令
在这里插入图片描述

#添加内容
sadd key value1 value2

#查询key里所有的值
smembers key

#移除key里面的某个value
srem key value

#随机移除某个value
spop key

#返回两个set的并集
sunion key1 key2

#返回key1踢出交集的那部分(差集)
sdiff key1 key2

#返回key1,key2交集
sinter key1 key2

实操

# 添加内容
>sadd nums1 1 1 2 2 3 3
3

#查询key里所有的值
>smembers key
1
2
3

#移除key里面的某个value
>srem nums1 1
1

#随机移除某个value
> spop nums
3

#返回两个set的并集
>sunion nums1 nums2
2
3
4

#返回key1踢出交集的那部分(差集)
>sdiff nums1 nums2

#返回key1,key2交集
>sinter nums1 nums2
2
3

五、有序集合(Zset)

Zset是Redis类似于SortedSet和HashMap的结合体,一方面它是一个set,保证了内部value的唯一性,另一方面它可以给每个value赋予一个score,代表这个value的排序权重。内部使用HashMap和跳跃表(SkipList)来保证数据的存储和有序,HashMap里放的是成员到score的映射,而跳跃表里存放的是所有的成员,排序依据是HashMap里存的score,使用跳跃表的结构可以获得比较高的查找效率,并且在实现上比较简单。sorted sets中最后一个 value被移除后,数据结构自动删除,内存被回收。

应用场景
主要应用于根据某个权重进行排序的队列的场景,比如游戏积分排行榜,设置优先级的任务列表,学生成绩表等。

操作指令
在这里插入图片描述

#添加元素
zadd key score value [score value...]

#获取集合的值并按照score从小到大排列,最小的是最上面
zrange key start end

#返回有序集key中,所有score 值介于min和max之间(包括等于min或max)的
#成员。有序集成员按score值递增(从小到大)次序排列,最小的是最上面

操作

#添加元素
>zadd rank 66 zhangsan 88 lisi 77 wangwu 99 zhaoliu
4


#获取集合的值并按照score从小到大排列,最小的是最上面
>zrange rank 0 3
zhangsan
wangwu
lisi
zhaoliu
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蒟丿蒻

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值