redis 基础数据类型
Sting类型 :
Redis 的字符串是动态字符串,是可以修改的字符串,内部结构实现上类似于 Java 的 ArrayList,采用预分配冗余空间的方式来减少内存的频繁分配,如图中所示,内部为当前字符串实际分配的空间 capacity 一般要高于实际字符串长度 len。当字符串长度小于 1M 时,扩容都是加倍现有的空间,如果超过 1M,扩容时一次只会多扩 1M 的空间。需要注意的是字符串最大长度为 512M。
操作命令:
set key value
get key
exists key
del key
批量设置
mset key1 value1 key2 value2 key3 value3
mget key1 key2 key3
过期设置
expire key1 5 5秒后过期
setex key 5 value #5s 后过期,等价于 set+expire
setnx key value 没有key 返回1设置成功,key已存在 返回0
计数
incr key # 将key对应的value值 递增加1 ,递增若超过最大数值则报错 (incrby age 5 按5递增)
list类型 :
Redis 的列表相当于 Java 语言里面的 LinkedList,注意它是链表而不是数组。这意味着 list 的插入和删除操作非常快,时间复杂度为 O(1),但是索引定位很慢,时间复杂度为 O(n),这点让人非常意外。
当列表弹出了最后一个元素之后,该数据结构自动被删除,内存被回收。
操作命令:
rpush key value1 value2 value3 存放元素 value1在最左边
llen key 查询list长度
lpop key 从左边取出对应的key的值,取出就没有了 (右边进左边出:队列 )
rpop key 从右边取出对应的key的值,取出就没有了 (右边进右边出:栈 )
慢操作
lindex 相当于 Java 链表的get(int index)方法,它需要对链表进行遍历,性能随着参数index增大而变差,
index可以为负数,index=-1表示倒数第一个元素,同样index=-2表示倒数第二个元素。
lindex key 1 取出下标为1,也就是放进去的第二个元素 O(n) 慎用
lrange key 0 -1 # 获取所有元素,O(n) 慎用
ltrim key 1 -1 为了截取下标为1 一直到最后 若区间为负数则清空列表 ltrim key 1 0
快速列表
首先在列表元素较少的情况下会使用一块连续的内存存储,这个结构是ziplist,也即是压缩列表。它将所有的元素紧挨着一起存储,分配的是一块连续的内存。当数据量比较多的时候才会改成quicklist。因为普通的链表需要的附加指针空间太大,会比较浪费空间,而且会加重内存的碎片化。比如这个列表里存的只是 int 类型的数据,结构上还需要两个额外的指针 prev 和 next 。所以 Redis 将链表和 ziplist 结合起来组成了 quicklist。也就是将多个 ziplist 使用双向指针串起来使用。
hash (字典):数组 + 链表二维结构 值只能是字符串
Java 的 HashMap 在字典很大时,rehash 是个耗时的操作,需要一次性全部 rehash。Redis 为了高性能,不能堵塞服务,所以采用了渐进式 rehash 策略。渐进式 rehash 会在 rehash 的同时,保留新旧两个hash结构,查询时会同时查询两个hash结构,然后在后续的定时任务中以及 hash 操作指令中,循序渐进地将旧 hash 的内容一点点迁移到新的 hash 结构中。当搬迁完成了,就会使用新的hash结构取而代之。
hash可以存储一个结构体部分字段数据,比如String类型数据若一次序列化整个结构存储导致网络流量浪费。hash也有缺点存储消耗大于单个字符串。根据实际情况来选择 hash还是string来存储
操作命令:
hset books java "think in java" # 命令行的字符串如果包含空格,要用引号括起来 若是更新操作直接覆盖
hget books java
hgetall books
批量 set
hmset books java "effective java" python "learning python" golang "modern golang programming"
计数
hincrby user-laoqian age 1
应用:存放数据对象
set类型:(集合)
Redis 的集合相当于 Java 语言里面的 HashSet,它内部的键值对是无序的唯一的。它的内部实现相当于一个特殊的字典,字典中所有的 value 都是一个值NULL。当集合中最后一个元素移除之后,数据结构自动删除,内存被回收。
操作命令:
sadd key value 成功返回1 失败返回0
sadd key value1 value2 成功返回2 失败返回0
smembers key # 注意顺序,和插入的并不一致,因为 set 是无序的 查出所有
sismember key value # 查询某个 value 是否存在,相当于 contains(o) 存在返回1 不存在返回0
scard books # 获取长度相当于 count()
spop books # 弹出一个 随机
应用 set 结构可以用来存储活动中奖的用户 ID,因为有去重功能,可以保证同一个用户不会中奖两次。
zset类型: (有序列表)
zset 内部的排序功能是通过「跳跃列表」数据结构来实现的,它的结构非常特殊,也比较复杂。
操作命令:
zadd key score value 按score来排序
zrange key 0 -1 # 按 score 排序列出,参数区间为排名范围 全部取出
zrevrange key 0 -1 # 按 score 逆序列出,参数区间为排名范围
zcard key # 获取长度相当于 count()
zscore key value # 获取指定 value 的 score # 内部 score 使用 double 类型进行存储,所以存在小数点精度问题
zrank key value # 排名
zrangebyscore key 0 8.91 # 根据分值区间遍历 zset
zrangebyscore books -inf 8.91 withscores # 根据分值区间 (-∞, 8.91] 遍历 zset,同时返回分值。inf 代表 infinite,无穷大的意思。
zrem key value # 删除 value
应用:zset 可以用来存粉丝列表,value 值是粉丝的用户 ID,score 是关注时间。我们可以对粉丝列表按关注时间进行排序。
zset 还可以用来存储学生的成绩,value 值是学生的 ID,score 是他的考试成绩。我们可以对成绩按分数进行排序就可以得到他的名次。
容器型数据结构的通用规则:
list/set/hash/zset 这四种数据结构是容器型数据结构,它们共享下面两条通用规则:
create if not exists
如果容器不存在,那就创建一个,再进行操作。比如 rpush 操作刚开始是没有列表的,Redis 就会自动创建一个,然后再 rpush 进去新元素。
drop if no elements
如果容器里元素没有了,那么立即删除元素,释放内存。这意味着 lpop 操作到最后一个元素,列表就消失了。
过期时间:
Redis 所有的数据结构都可以设置过期时间,时间到了,Redis 会自动删除相应的对象。需要注意的是过期是以对象为单位,比如一个 hash 结构的过期是整个 hash 对象的过期,而不是其中的某个子 key。
还有一个需要特别注意的地方是如果一个字符串已经设置了过期时间,然后你调用了 set 方法修改了它,它的过期时间会消失。
有疑问加站长微信联系(非本文作者)