Redis的基本数据类型

Redis共五种基本数据类型:string、list、hash、set和zset

一、string

Redis的字符串是动态字符串,采用预分配冗余空间的方式来减少内存的频繁分配。当字符串长度小于1M时,扩容方式为翻倍空间,如果超过1M,扩容时一次只会多扩1M的空间。需要注意的是:字符串最大长度为512M。

set ireader helloworld //初始化字符串
get ireader //获取字符串内容
strlen ireader //获取字符串长度
getrange ireader 3 6 //获取字符串子串
setrange ireader 4 aaa //覆盖子串,长度为替换的字符串长度
append ireader hhhh //追加子串

//若字符串内容为整数,可以当计算器来使用,计数器是有范围的,它不能超过Long.Max,不能低于Long.MIN
incrby ireader 100
decrby ireader 100
incr ireader //等价于 incrby ireader 1
decr ireader //等价于 decrby ireader 1

expire ireader 60 //60秒后过期删除,返回1表示设置成功,返回0表示ireader不存在
ttl ireader //返回剩余过期时间,返回-2表示ireader不存在,返回-1表示没有设置过期时间

二、list

Redis中的list为双向链表,所以随机定位性能较弱,首位插入删除性能较优。

负下标 链表元素的位置使用自然数0,1,2,....n-1表示,还可以使用负数-1,-2,...-n来表示,-1表示「倒数第一」,-2表示「倒数第二」,那么-n就表示第一个元素,对应的下标为0。

队列/堆栈 链表可以从表头和表尾追加和移除元素,结合使用rpush/rpop/lpush/lpop四条指令,可以将链表作为队列或堆栈使用,左向右向进行都可以

rpush ireader java
lpush ireader go python
lpop ireader
rpop ireader

llen ireader //获取链表长度
lindex ireader 1 //读取指定位置元素
lrange ireader 0 2 //读取下标0-2的元素
lrange ireader 0 -1 //读取所有元素

lset ireader 1 javascript //修改指定位置元素
lrem ireader 1 java //需要指定删除的最大个数以及元素的值

ltrim ireader 1 5 //获取定长列表

补充:如果再深入一点,你会发现Redis底层存储的还不是一个简单的linkedlist,而是称之为快速链表quicklist的一个结构。首先在列表元素较少的情况下会使用一块连续的内存存储,这个结构是ziplist,也即是压缩列表。它将所有的元素紧挨着一起存储,分配的是一块连续的内存。当数据量比较多的时候才会改成quicklist。因为普通的链表需要的附加指针空间太大,会比较浪费空间。比如这个列表里存的只是int类型的数据,结构上还需要两个额外的指针prev和next。所以Redis将链表和ziplist结合起来组成了quicklist。也就是将多个ziplist使用双向指针串起来使用。这样既满足了快速的插入删除性能,又不会出现太大的空间冗余。

三、hash

Redis中的hash结构等价于Java中的HashMap结构,实现结构上为二维结构,第一维是数组,第二维是链表,hash的key和value存放在链表中,数组存放的是链表的头指针,链表的作用是串联【hash碰撞】


Redis的基本数据类型_第1张图片
hash结构图.png
hset ireader go fast //增加元素
hmset ireader java fast python small //增加多个元素
hget ireader go //获取单个元素
hmget ireader java python //获取多个元素
hgetall ireader //获取全部元素
hkeys ireader //获取所有key
hvals ireader //获取所有value
hdel iredaer java go //删除多个元素
hexists ireader go //判断元素是否存在

//hash结构还可以当计数器使用,若value不是整数,调用hincrby指令会出错
hincrby ireader java 1

扩容 当hash内部的元素比较拥挤时(hash碰撞比较频繁),就需要进行扩容。扩容需要申请新的两倍大小的数组,然后将所有的键值对重新分配到新的数组下标对应的链表中(rehash)。如果hash结构很大,比如有上百万个键值对,那么一次完整rehash的过程就会耗时很长。这对于单线程的Redis里来说有点压力山大。所以Redis采用了渐进式rehash的方案。它会同时保留两个新旧hash结构,在后续的定时任务以及hash结构的读写指令中将旧结构的元素逐渐迁移到新的结构中。这样就可以避免因扩容导致的线程卡顿现象。

缩容 Redis的hash结构不但有扩容还有缩容,从这一点出发,它要比Java的HashMap要厉害一些,Java的HashMap只有扩容。缩容的原理和扩容是一致的,只不过新的数组大小要比旧数组小一倍。

四、set

Java程序员都知道HashSet的内部实现使用的是HashMap,只不过所有的value都指向同一个对象。Redis的set结构也是一样,它的内部也使用hash结构,所有的value都指向同一个内部值。

sadd ireader go java python //增加元素(可多个)
smembers ireader //获取所有元素
scard ireader //获取集合长度
srandmember ireader //随机获取count个元素,默认个数为1

srem ireader go java //删除一个到多个元素
spop ireader //spop删除一个随机元素

sismember ireader java //判断单个元素是否存在

五、zset

zset是Redis提供的一个非常特别的数据结构,一方面它等价于Java的数据结构Map,可以给每一个元素value赋予一个权重score,另一方面它又类似于TreeSet,内部的元素会按照权重score进行排序,可以得到每个元素的名次,还可以通过score的范围来获取元素的列表。
zset底层实现使用了两个数据结构,第一个是hash,第二个是跳跃列表,hash的作用就是关联元素value和权重score,保障元素value的唯一性,可以通过元素value找到相应的score值。跳跃列表的目的在于给元素value排序,根据score的范围获取元素列表。

Redis的基本数据类型_第2张图片
跳表结构.png
zadd ireader 4 python 1 java 2 go //添加元素
zcard ireader //通过指令zcard可以得到zset的元素个数
zrem ireader go java //删除元素y
zincrby ireader 1 python //计数器
zscore ireader python //获取分数
zrank ireader java //获取排名

zrange ireader 0 -1 //获取所有元素
zrange ireader 0 -1 withscores //获取所有元素和分数,按分数从小到大
zrevrange ireader 0 -1 withscores //按分数从大到小

zrangebyscore ireader 0 5 //通过zrangebyscore指令指定score范围获取对应的元素列表。
zrangebyscore ireader -inf +inf withscores //正向是由小到大,负向是由大到小。参数-inf表示负无穷,+inf表示正无穷。
zrevrangebyscore ireader -inf +inf withscores

zremrangebyrank ireader 0 1 //删除范围内的元素
zremrangebyscore ireader -inf 4 //删除分数范围内的元

你可能感兴趣的:(Redis的基本数据类型)