Redis 支持的数据类型
Redis 五大数据类型
String(字符串)
适用场景:缓存业务信息,且只是根据 key 直接获取缓存 value,不需要排序,去重等功能。
String 是 Redis 种最简单的数据结构,但是却是大家日常使用频率最高的数据结构,它使用简单,并且扩展性非常强,我们可以设置普通的字符串,也可以设置json,存取速度也是最快的。
字符串存储的底层结构其实就是字符数组。
这个字符串是动态的,是可以修改的。内部采用预分配冗余空间的方式来减少内存的频繁分配。
当存储的字符大小 <= 1M ,都是翻倍扩容。
如果存储的字符串大小 >1M ,则每次之扩容1M空间。
示例操作
//复制 test 为 wanji
127.0.0.1:6379[4]> set test wanji
OK
// 获取 test 的 value 值
127.0.0.1:6379[4]> get test
"wanji"
//查看这个数据库下所有的key
127.0.0.1:6379[4]> keys *
1) "test"
//删除 test
127.0.0.1:6379[4]> del test
(integer) 1
127.0.0.1:6379[4]> keys *
(empty array)
//一次性设置多个值 mset value key value key
127.0.0.1:6379[4]> mset hello world java best
OK
//获取多个值
127.0.0.1:6379[4]> mget hello java
1) "world"
2) "best"
127.0.0.1:6379[4]> set sex 18
OK
//key值自增
127.0.0.1:6379[4]> incr sex
(integer) 19
127.0.0.1:6379[4]> get sex
"19"
//key值自减
127.0.0.1:6379[4]> decr sex
(integer) 18
127.0.0.1:6379[4]> get sex
"18"
//key值自增指定步长
127.0.0.1:6379[4]> incrby sex 2
(integer) 20
127.0.0.1:6379[4]> get sex
"20"
//key值自减指定步长
127.0.0.1:6379[4]> decrby sex 2
(integer) 18
ttl
如果键有设置过期时间,当键过期或者被删除了,TTL 命令返回-2,当键没有设置过期时间,表示是永久的,TTL 命令 返回 -1
127.0.0.1:6379[4]> ttl test
(integer) -1
/*设置 test
注意:注意,假如 test 已存在,那么该语句会更新 test 的 value 为 wanji,并且过期时间设置为 10 秒
*/
127.0.0.1:6379[4]> expire test 10
(integer) 1
127.0.0.1:6379[4]> setex test 10 wanji
OK
//查看 test 还有多久过期
127.0.0.1:6379[4]> ttl test
(integer) -2
//如果 test 存在,就不赋
127.0.0.1:6379[4]> setnx test bob
(integer) 1
127.0.0.1:6379[4]> get test
"bob"
//计算 value 值长
127.0.0.1:6379[4]> strlen test
(integer) 3
字符串内部实现——int编码&raw编码&embstr编码
3种encoding:什么情况下,选择哪种encoding?
-
int
设置为 long 类型表示的整数,那么 encoding 是 int。
127.0.0.1:6379[2]> set num 20 OK 127.0.0.1:6379[2]> get num "20" 127.0.0.1:6379[2]> object encoding num "int"
-
embstr
当我们保存的值小于40的时候,则使用是embstr
专门用户保存短字符串的一种编码方式。优点:快
raw 调用两次的内存分配函数来分别创建redisObject,sdshdr。
embstr 通过一次内存分配函数来分配一块连续的空间,包含着redisObject,sdshdr。所以执行速度快。
embstr 没有提供修改函数,所以只读的。我们对它进行修改的化,首先转换成raw,在执行修改,然后结束。
127.0.0.1:6379[2]> set name wanji OK 127.0.0.1:6379[2]> object encoding name "embstr" 127.0.0.1:6379[2]> append name WanJiRedis (integer) 15 127.0.0.1:6379[2]> object encoding name "raw"
-
raw
127.0.0.1:6379[2]> set num 201215121002020220220020202022020230303030303 OK 127.0.0.1:6379[2]> get num "201215121002020220220020202022020230303030303" 127.0.0.1:6379[2]> object encoding num "raw"
-
编码转换规则
如果将原本保存的整数值转换为字符串值,那么字符串对象的编码也将从 int
127.0.0.1:6379[2]> set num 1234
OK
127.0.0.1:6379[2]> OBJECT encoding num
"int"
127.0.0.1:6379[2]> APPEND num a
(integer) 5
127.0.0.1:6379[2]> get num
"1234a"
127.0.0.1:6379[2]> OBJECT encoding num
"raw"
List(列表)
-
适用场景:消息队列。
-
它的特点就是内部元素有序、重复,并且插入和删除很快O(1),但是查找却很慢O(n)。功能支持队列和栈操作。
-
Redis列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)
一个列表最多可以包含 232 - 1 个元素 (4294967295, 每个列表超过40亿个元素)。
示例操作
//左侧插入
lpush msg_queue msg1 msg2 msg3
//右侧插入
rpush msg_queue msg1 msg2 msg3
//左侧弹出
lpop msg_queue
//右侧弹出
rpop msg_queue
//查看列表长度
llen msg_queue
//查看列表中某个index的值 下标从0开始,要注意的是:由于这个操作是要遍历列表,所以index越大,效率越差。
lindex msg_queue 2
//查看msg_queue里面所有元素
lrange msg_queue 0 -1
列表操作
内部实现
列表对象的编码支持 ziplist 和 linkedlist 两种
ziplist
ziplist 编码列表对象,采用压缩列表实现。每个列表节点保存一个列表中的元素。
127.0.0.1:6379> RPUSH testlist a b c
(integer) 3
linkedlist
linkedlist编码列表对象,采用双向链表作为底层实现,每个列表节点保存一个列表中的元素。
编码转换规则
-
同时满足一下两个条件时,是ziplist类型,否则为linkedlist类型
-
条件1:列表中所有元素长度都小于66字节。
-
条件2:列表中元素的个数小于512个。
Set(集合)
概述
- 适用场景:存储有去重需求的数据,比如:针对一篇文章用户进行点赞操作。
- 它的特点是内部元素无序且不重复。它的内部实现相当于一个特殊的字典,字典中所有的value指都为NULL。
具体操作
//添加元素到集合中
127.0.0.1:6379> sadd likeset Bob Tom Jreey
(integer) 3
//查看集合中的所有元素 输出顺序是乱序的
127.0.0.1:6379> smembers likeset
1) "Jreey"
2) "Bob"
3) "Tom"
//但是如果添加的是纯数字 输出顺序是有序的
127.0.0.1:6379> sadd numbers 2 5 6 7 1 9 8 3
(integer) 8
127.0.0.1:6379> smembers numbers
1) "1"
2) "2"
3) "3"
4) "5"
5) "6"
6) "7"
7) "8"
8) "9"
//查询 Tom 是否在集合中
127.0.0.1:6379> sismember likeset Tom
(integer) 1
//查询集合的长度
127.0.0.1:6379> scard likeset
(integer) 3
//取出集合中的一个元素
127.0.0.1:6379> spop likeset
"Tom"
//删除
127.0.0.1:6379> del likeset
(integer) 1
内部实现
- 集合对象的编码可以是intset或hashtable。
intset(证书集合)
-
intset编码集合对象使用整数集合作为底层实现,集合对象包含的所有元素都被保存在整数集合里面。
127.0.0.1:6379> SADD number 1 2 3 4 (integer) 4 127.0.0.1:6379> OBJECT encoding number "intset"
数据结构如下:
hashtable
-
底层字典作为底层实现,每个键都是一个字符串对象,每个字符串对象包含了一个集合元素,而字典的值则全部被设置为NULL。
数据结构如下:
编码转换规则
- 当创建集合类型时,如果集合的元素个数小于512个,且元素都为整数是内部编码为intset ,采用intset为内部编码保存,如果元素和元素值不满足intset内部编码条件,则采用hashtable内部编码保存。
Zset(有序集合)
概述
- 适用场景:存储有去重且有序的数据,比如:学生的高考成绩。
- 它的内部采用“跳跃列表”实现。根据score进行排序。
具体操作
-
添加元素到sat_score中 注意,111 wanji会覆盖 134 wanji(注意删除原来存在的key)
zadd score 134 wanji 122 bob 156 john 111 wanji
-
查看hh的score值
zscore score wanji
-
正序输出 输出从下标0到下标-1(即倒数第一个)中的所有元素从小到大
zrange score 0 -1 zrangebyscore score -inf +inf # 与上面输出效果一样,输出score>=负无穷,score<=正无穷的所有元素
-
倒序输出
zrevrange score 0 -1
-
查看sat_score中的元素个数
zcard score 注意,是按照正序排序输出的,从0开始
-
获得sat_score中score>=2 且 score<=5的元素,正序排列
zrangebyscore score 111 123 zrangebyscore score 0 -1 会返回empty array,而并不是展示所有列表。因为score>=0 且score<=-1 是不存在的 zrangebyscore score (111 122 半括号,表示小于。不加半括号,表示小于等于 zrangebyscore score -inf 122 inf代表infinite:无穷的,-inf代表负无穷 +inf代表正无穷
-
获得sat_score中 score<=5 且score>=2的元素,倒序排列
zrevrangebyscore score 123 111
-
删除sat_score中的元素haha
zrem score wanji
内部实现:
- 有序集合编码的内部实现可以是ziplist或skiplist
ziplist
-
ziplist使用压缩列表作为底层实现,第一个节点保存元素的成员(member),而第二个节点则保存元素的分值(score)。压缩列表内的集合元素按分值从小到大进行排序。
127.0.0.1:6379> zadd sat_score 134 hi 122 bob 156 john (integer) 3 127.0.0.1:6379> OBJECT encoding sat_score "ziplist"
数据结构如下:
当ziplist作为zset的底层存储结构时候,每个集合元素使用两个紧挨在一起的压缩列表节点来保存,第一个节点保存元素的成员,第二个元素保存元素的分值。
skiplist
-
skiplist编码的有序集合采用zset结构作为底层实现,一个zset同时包含一个字典和一个跳跃表。
redis.h /* * redis对象 */ typedef struct zset { // 字典(用来做缓存) dict *dict; // 跳跃表(排序结构) zskiplist *zsl; } zset;
Hash(字典)
概述
- 适用场景:存储无序字典的数据,比如:适合存储对象类型。比如存储猪肉价格。
- 它的内部采用数组+链表的结构,类似java里的HashMap。
- hash的key值只能是字符串。将对象存储为hash结构可以针对需要来获取部分数据,而不是将整个对象获取。减少网络资源浪费。
- rehash采用了渐进式的策略。
具体操作
-
添加元素到 pig 中
hset pig leg "26rmb/kg" hset pig ear "30rmb/kg" hset pig tongue "40rmb/kg" hset pig trotters "60rmb/kg"
-
查询pig中猪耳朵的价格
hget pig ear
-
批量添加
hmset boys_weight mark 126g bob 99 john 179 tom 155
-
批量获取元素
hmget boys_weight mark john
-
获得pig中元素个数
hlen pig
-
查询pig中所有元素
hgetall pig
内部实现
- 哈希对象编码支持ziplist和hashtable两种。
ziplist
-
ziplist编码底层使用压缩列表实现,当有新的键值对要加入到哈希对象时,会先将key值从队尾推入压缩列表中,再将这个key对应的value值从队尾推入压缩列表中;所以,同一键值对的两个节点总是紧挨在一起的,key在前,value在后。
127.0.0.1:6379> hset hello name wanji (integer) 1 127.0.0.1:6379> hset hello age 20 (integer) 1 127.0.0.1:6379> hset hello sex male (integer) 1 127.0.0.1:6379> hgetall hello 1) "name" 2) "wanji" 3) "age" 4) "20" 5) "sex" 6) "male" 127.0.0.1:6379> OBJECT encoding hello "ziplist"
数据结构如下:
hashtable
编码转换规则:
-
同时满足两个条件时是ziplist编码类型,否则为hashtable编码类型
条件1:哈希对象中所有键值对中,key和value的长度均小于46字节。
条件2:哈希对象中键值对的个数小于512个。