redis深入学习-01—redis五大数据结构

redis五大数据结构:string、list、hash、set、zset。
redis的数据结构是一个全局的Map结构,五大数据结构是值value的结构,用java表示,可以理解为Map<String,String>,Map<String,List>,Map<String,Set>,Map<String,String>,Map<String,Zset>。

1. string类型。

redis的字符串是动态字符串,即value类型为字符串时,其实是分配了一个数组来存放这个字符串的每个字符。如java的ArrayList。字符串最大长度是512MB,当小于1MB时,扩容时会加倍当前的容量,

当超过1MB后,每次扩容会加1MB。数据结构如下图所示。

1.1 value结构

字符串由多个字符组成,每个字符由8个bit位组成。所以字符串可以看成是多个bit位的组成。

1.1 操作命令

----------------------------创建数据操作------------------------
//单key值添加
set key value

//单key值查询
get key 

//批量添加
mset key1 key2 key3...

//批量查询
mget key1 key2 key3...

//过期操作:10s后过期
expire key 10

//10s后过期,等价于 set+expire
setex key 10 value

//如果key不存在就执行set命令创建,如果存在就创建失败。分布式锁的实现。
setnx key value


----------------------------计数操作------------------------
//value值是整数的话可以进行计数操作,操作的数是有个范围的,超过Long.MAX会报错,大约是922万亿。
//也不能小于起始值。否则都会报错。
set jll 1

//对jll这个key进行+1操作
incr jll

//对jll这个key进行+2操作
incrby jll 2

//对jll这个key进行-2操作
incrby jll -2

2. list类型(列表)

Redis中的list类型,底层实现其实是链表结构,相当于java中的LinkedList。所以它的插入和删除复杂度为O(1),查询复杂度为O(N)。这个链表是个双向链表,所以能双向遍历读取。

结构如图2.1。

2.1

2.1 Redis中的list可以用来做队列使用:右边进左边出,右边进右边出。

右边进左边出:

//初始化一个队列
rpush student s1 s2 s3

//查询队列元素个数
llen student

//从左边取一个元素,取完后队列中就没有了s1这个元素。执行3次,队列中元素为空
lpop student

右边进右边出:

//初始化一个队列
rpush student s1 s2 s3

//从右边进右边出,下面命令会取出元素 s3。执行3次,元素为空。
rpop student

2.2 redis中 list 的慢操作,虽然是慢操作,但是根据使用场景,再一定的数据量下使用完全没有问题,数据量大的情况下慎用:

lindex:获取列表中某一位置的元素,如:lindex list 1 ---> 获取列表1索引位置为1的元素。

ltrim:定义列表某一区间的元素为一个列表,区间之外的元素删掉,如:一个list 有[1,2,3...20]20个元素,ltrim list 0 10 --->把这个list列表修改为[1,2,3...10]为10个元素的列表。然后执行 lrange list 0 -1 读取list所有元素为 [1,2,3...10],没修改执行读取的应为[1,2,3...20]。

lrange:遍历list列表元素。如: lrange list 0 10 --->读取list列表0到10号的元素。lrange list 0 -1 ---> 读取list列表所有元素。-1表示倒数第一个元素。-2表示倒数第二个元素。

2.3 redis中list慢操作的改进

2.2说的是redis的list是一个慢操作,但是redis底层实现其实是一个quicklist(快速列表)。它不是一个简单的linkedlist,它是一个ziplist+linkedlist。

ziplist:一个压缩列表,即 数据量少的时候是一个内存上空间连续的内存。

linkedlist:当数据量大的时候,它会是一个多个ziplist通过双向指针链接的list。

如下图所示:

2.2.1

3. hash字典

首先要说的是Redis中的hash字典和java中的HashMap的实现基本一样,都是数组+链表的数据结构。不同的是,它们的扩容机制不太一样,而且存储类型不一样,redis中hash的值只允许字符串。redis的存储和读取是高效的,基本不允许堵塞请求,而扩容是个耗时的操作,所以redis中的hash表的扩容是循序渐进的。

渐进式扩容:扩容的同时,会新建一个新的hash表,保留老的hash表,请求去读的时候会同时读取两个hash表,在后续的hash操作指令中,循序渐进的将上一版本的hash的内容迁移到新版本中,当搬迁完成时,会移除老版本中的最后一个元素,然后老hash会被内存回收,完成扩容。

从 String类型和hash类型的数据结构比较,我们不难发现,存储相同内容的数据,hash表存储更消耗内存,但是hash表中的子属性内容读取速度更快。如存储一个User对象,User对象中有age属性,那么存储User的时候,如果用string类型,那么底层是一个连续的数组,而用hash存储,是一个hashMap,所以hash更耗费内存,但是读取age的时候,hash更快。

hash的相关命令:

//创建hash表并存放数据
hset student xiaoming 1
hset student xiaohua 2

//从hash表中取值
hget student xiaoming

//获取所有student
hgetall student

//获取student的元素数量
hlen student

//批量存储元素
hmset student xiaoming 1 xiaohua 2

//批量获取student的元素
hmget student xiaoming xiaohua

//计数 +1
hincrby student xiaohua a

4. set 集合

Redis的集合相当于Java语言里面的HashSet,它内部的键值对是无序的、唯一的。java中的HashSet底层其实也是HashMap实现的,复杂度低查询快。它的内部实现相当于一个特殊的字典,字典中所有的value都是一个值NULL。当集合中最后一个元素被移除之后,数据结构被自动删除,内存被回收。所以Redis中的set可以使用在需要保持数据唯一性的场景。

set的相关命令:

//给user添加数据
sadd user xiaoming

//批量添加
sadd user ww ss gg

//查询user的数据
smembers user

//查询user中是否存在ww
sismember user ww

//查询某一个key中的数据的数量
scard user

//弹出一个元素
spop user

5. zset 集合

zset 比 set 集合多一个排序的功能。它类似于 Java 的 SortedSet 和 HashMap 的结合体,一方面它是个set,保证了内部value的唯一,另一方面它可以给每个value赋予一个score,代表这个value排序权重。它的排序的底层实现用的是“跳表”的数据结构实现,对“跳表”数据结构感兴趣的可以参考其他文章。zset 和 set 一样,最后一个元素被删除之后,数据结构都会被删除,内存被回收。项目中某一项业务数据需要排序的时候,可以考虑使用zset。

//添加数据,score内部存的是double类型,取值的时候有可能存在精度问题
zadd xiaoming 50.0 "math"
zadd xiaoming 50.0 "yuwen"


//根据 key 取出所有元素并且按照 score 值升序排列
zrange xiaoming 0 -1

//统计key的所有元素
zcard xiaoming

//获取key的某一个元素的分数
zscore xiaoming "math"

//按照score的逆序列出,即按照score值降序排列
zrevrange xiaoming 0 -1

//统计某一key中存的元素数量
zcard xiaoming

//获取某一key的某一元素的排名
zrank xiaoming "math"

//获取某一key score区间的元素
zrangebyscore xiaoming 0 60.0

//获取某一key score区间的元素,并返回分值。-inf(infinite) 为负无穷大
zrangebyscore xiaoming -inf 60.0 withscores

//删除某一key中的指定元素
zrem xiaoming "math"


6. redis中过期时间的使用注意点

redis中的5大数据结构都可以设置过期时间,但是过期时间是相对于对象的,不是指容器中的某一具体元素。如hash表中存了很多元素,当设置hash表对应的key的过期时间后,当过期时,整个hash表中数据都会过期。

需要注意的另一个问题,如果一个字符串已经设置了过期时间,如果你调用了它的set方法,那么它的过期时间会消失。可以通过命令验证。

set user xiaoming

//过期时间设置
expire user 10000

//过期时间查询
ttl user

//修改user
set user zhangsan

//再次查询过期时间
ttl user

7. redis中数据list、hash、set、zset容器型数据结构的使用规则

1. create if not exists:  如果容器不存在,存放对象的元素的时候,创建一个数据结构再操作。

2. drop if no elements: 如果容器中最后一个元素被删除,会删除这个数据结构。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

荆茗Scaler

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

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

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

打赏作者

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

抵扣说明:

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

余额充值