1 字符串(String)
String是简单的 key-value 键值对,value 不仅可以是 String,也可以是数字。String在redis内部存储默认就是一个字符串,被redisObject所引用,当遇到incr,decr等操作时会转成数值型进行计算,此时redisObject的encoding字段为int。
String在redis内部存储默认就是一个字符串,被redisObject所引用,当遇到incr,decr等操作时会转成数值型进行计算,此时redisObject的encoding字段为int。
1.1 应用场景
String是最常用的一种数据类型,普通的key/value存储都可以归为此类,这里就不所做解释了。
1.2 相关命令
命令 |
描述 |
SET |
设置指定 key 的值 |
GET |
获取指定 key 的值 |
GETRANGE |
返回 key 中字符串值的子字符 |
GETSET |
将给定 key 的值设为 value ,并返回 key 的旧值 ( old value ) |
GETBIT |
对 key 所储存的字符串值,获取指定偏移量上的位 ( bit ) |
MGET |
获取所有(一个或多个)给定 key 的值 |
SETBIT |
对 key 所储存的字符串值,设置或清除指定偏移量上的位(bit) |
SETEX |
设置 key 的值为 value 同时将过期时间设为 seconds |
SETNX |
只有在 key 不存在时设置 key 的值 |
SETRANGE |
从偏移量 offset 开始用 value 覆写给定 key 所储存的字符串值 |
STRLEN |
返回 key 所储存的字符串值的长度 |
MSET |
同时设置一个或多个 key-value 对 |
MSETNX |
同时设置一个或多个 key-value 对 |
PSETEX |
以毫秒为单位设置 key 的生存时间 |
INCR |
将 key 中储存的数字值增一 |
INCRBY |
将 key 所储存的值加上给定的增量值 ( increment ) |
INCRBYFLOAT |
将 key 所储存的值加上给定的浮点增量值 ( increment ) |
DECR |
将 key 中储存的数字值减一 |
DECRBY |
将 key 所储存的值减去给定的减量值 ( decrement ) |
APPEND |
将 value 追加到 key 原来的值的末尾 |
1.3 操作例子
127.0.0.1:6379> setex channelname 60 学习是我快乐
OK
127.0.0.1:6379> ttl channelname
(integer) 40
超过60秒后
127.0.0.1:6379> get channelname
(nil)
127.0.0.1:6379> setnx author huanxi
(integer) 1
第2次执行失败
127.0.0.1:6379> setnx author huanxi
(integer) 0
127.0.0.1:6379> incr spend
(integer) 1
127.0.0.1:6379> incr spend
(integer) 2
127.0.0.1:6379> incr spend
(integer) 3
127.0.0.1:6379> get spend
"3"
127.0.0.1:6379> getset language java
(nil)
127.0.0.1:6379> getset language go
"java"
127.0.0.1:6379> getset language rust
"go"
2 哈希(Hash)
Redis Hash对应Value内部实际就是一个HashMap,实际这里会有2种不同实现,这个Hash的成员比较少时Redis为了节省内存会采用类似一维数组的方式来紧凑存储,而不会采用真正的HashMap结构,对应的value redisObject的encoding为zipmap,当成员数量增大时会自动转成真正的HashMap,此时encoding为ht。
2.1 应用场景
假设有多个用户及对应的用户信息,可以用来存储以用户ID为key,将用户信息序列化为比如json格式做为value进行保存。
2.2 相关命令
命令 |
描述 |
HDEL |
删除一个或多个哈希表字段 |
HEXISTS |
查看哈希表 key 中,指定的字段是否存在 |
HGET |
获取存储在哈希表中指定字段的值 |
HGETALL |
获取在哈希表中指定 key 的所有字段和值 |
HINCRBY |
为哈希表 key 中的指定字段的整数值加上增量 increment |
HINCRBYFLOAT |
为哈希表 key 中的指定字段的浮点数值加上增量 increment |
HKEYS |
获取所有哈希表中的字段 |
HLEN |
获取哈希表中字段的数量 |
HMGET |
获取所有给定字段的值 |
HMSET |
同时将多个 field-value (域-值)对设置到哈希表 key 中 |
HSET |
将哈希表 key 中的字段 field 的值设为 value |
HSETNX |
只有在字段 field 不存在时,设置哈希表字段的值 |
HVALS |
获取哈希表中所有值 |
HSCAN |
迭代哈希表中的键值对 |
HSTRLEN |
返回哈希表 key 中, 与给定域 field 相关联的值的字符串长度 |
2.3 操作例子
127.0.0.1:6379> hset person name jack
(integer) 1
127.0.0.1:6379> hset person age 20
(integer) 1
127.0.0.1:6379> hset person sex famale
(integer) 1
127.0.0.1:6379> hgetall person
1) "name"
2) "jack"
3) "age"
4) "20"
5) "sex"
6) "famale"
127.0.0.1:6379> hkeys person
1) "name"
2) "age"
3) "sex"
127.0.0.1:6379> hvals person
1) "jack"
2) "20"
3) "famale"
3 列表(List)
Redis list的实现为一个双向链表,即可以支持反向查找和遍历,更方便操作,不过带来了部分额外的内存开销,Redis内部的很多实现,包括发送缓冲队列等也都是用的这个数据结构。
3.1 应用场景
Redis list的应用场景非常多,也是Redis最重要的数据结构之一,比如twitter的关注列表、粉丝列表等都可以用Redis的list结构来实现,再比如有的应用使用Redis的list类型实现一个简单的轻量级消息队列,生产者push,消费者pop/bpop。
3.2 相关命令
命令 |
描述 |
BLPOP |
移出并获取列表的第一个元素 |
BRPOP |
移出并获取列表的最后一个元素 |
BRPOPLPUSH |
从列表中弹出一个值,并将该值插入到另外一个列表中并返回它 |
LINDEX |
通过索引获取列表中的元素 |
LINSERT |
在列表的元素前或者后插入元素 |
LLEN |
获取列表长度 |
LPOP |
移出并获取列表的第一个元素 |
LPUSH |
将一个或多个值插入到列表头部 |
LPUSHX |
将一个值插入到已存在的列表头部 |
LRANGE |
获取列表指定范围内的元素 |
LREM |
移除列表元素 |
LSET |
通过索引设置列表元素的值 |
LTRIM |
对一个列表进行修剪(trim) |
RPOP |
移除并获取列表最后一个元素 |
RPOPLPUSH |
移除列表的最后一个元素,并将该元素添加到另一个列表并返回 |
RPUSH |
在列表中添加一个或多个值 |
RPUSHX |
为已存在的列表添加值 |
3.3 操作例子
redis 127.0.0.1:6379> lpush list1 redis
(integer) 1
redis 127.0.0.1:6379> lpush list1 hello
(integer) 2
redis 127.0.0.1:6379> rpush list1 world
(integer) 3
redis 127.0.0.1:6379> llen list1
(integer) 3
redis 127.0.0.1:6379> lrange list1 0 3
1) "hello"
2) "redis"
3) "world"
redis 127.0.0.1:6379> lpop list1
"hello"
redis 127.0.0.1:6379> rpop list1
"world"
redis 127.0.0.1:6379> lrange list1 0 3
1) "redis"
4 集合(Set)
可以理解为一堆值不重复的列表,类似数学领域中的集合概念,且Redis也提供了针对集合的求交集、并集、差集等操作。
set 的内部实现是一个 value永远为null的HashMap,实际就是通过计算hash的方式来快速排重的,这也是set能提供判断一个成员是否在集合内的原因。
4.1 应用场景
Redis set对外提供的功能与list类似是一个列表的功能,特殊之处在于set是可以自动排重的,当你需要存储一个列表数据,又不希望出现重复数据时,set是一个很好的选择,并且set提供了判断某个成员是否在一个set集合内的重要接口,这个也是list所不能提供的。
又或者在微博应用中,每个用户关注的人存在一个集合中,就很容易实现求两个人的共同好友功能。
4.2 相关命令
命令 |
描述 |
SADD |
向集合添加一个或多个成员 |
SCARD |
获取集合的成员数 |
SDIFF |
返回给定所有集合的差集 |
SDIFFSTORE |
返回给定所有集合的差集并存储在 destination 中 |
SINTER |
返回给定所有集合的交集 |
SISMEMBER |
判断 member 元素是否是集合 key 的成员 |
SMEMBERS |
返回集合中的所有成员 |
SMOVE |
将 member 元素从 source 集合移动到 destination 集合 |
SPOP |
移除并返回集合中的一个随机元素 |
SRANDMEMBER |
返回集合中一个或多个随机数 |
SREM |
移除集合中一个或多个成员 |
SUNION |
返回所有给定集合的并集 |
SUNIONSTORE |
所有给定集合的并集存储在 destination 集合中 |
SSCAN |
迭代集合中的元素 |
4.3 操作例子
127.0.0.1:6379> sadd skill golang
(integer) 1
127.0.0.1:6379> sadd skill java
(integer) 1
127.0.0.1:6379> sadd skill python
(integer) 1
127.0.0.1:6379> sadd skill java
(integer) 0
127.0.0.1:6379> sadd skill2 rust
(integer) 1
127.0.0.1:6379> sadd skill2 golang
(integer) 1
127.0.0.1:6379> sadd skill2 typescript
(integer) 1
127.0.0.1:6379> smembers skill
1) "python"
2) "java"
3) "golang"
127.0.0.1:6379> smembers skill2
1) "typescript"
2) "golang"
3) "rust"
127.0.0.1:6379> scard skill
(integer) 3
127.0.0.1:6379> SISMEMBER skill golang
(integer) 1
127.0.0.1:6379> sinter skill skill2
1) "golang"
127.0.0.1:6379> sdiff skill skill2
1) "python"
2) "java"
127.0.0.1:6379> sunion skill skill2
1) "golang"
2) "python"
3) "java"
4) "rust"
5) "typescript"
5 有序集合(sorted set)
Redis有序集合类似Redis集合,不同的是增加了一个功能,即集合是有序的。一个有序集合的每个成员带有分数,用于进行排序。
Redis有序集合添加、删除和测试的时间复杂度均为O(1)(固定时间,无论里面包含的元素集合的数量)。列表的最大长度为2^32- 1元素(4294967295,超过40亿每个元素的集合)。
Redis sorted set的内部使用HashMap和跳跃表(SkipList)来保证数据的存储和有序,HashMap里放的是成员到score的映射,而跳跃表里存放的是所有的成员,排序依据是HashMap里存的score,使用跳跃表的结构可以获得比较高的查找效率,并且在实现上比较简单。
5.1 应用场景
Redis sorted set的使用场景与set类似,区别是set不是自动有序的,而sorted set可以通过用户额外提供一个优先级(score)的参数来为成员排序,并且是插入有序的,即自动排序。当你需要一个有序的并且不重复的集合列表,那么可以选择sorted set数据结构,比如twitter 的public timeline可以以发表时间作为score来存储,这样获取时就是自动按时间排好序的。
又比如用户的积分排行榜需求就可以通过有序集合实现。还有上面介绍的使用List实现轻量级的消息队列,其实也可以通过Sorted Set实现有优先级或按权重的队列。
5.2 相关命令
命令 |
描述 |
ZADD |
向有序集合添加一个或多个成员,或者更新已存在成员的分数 |
ZCARD |
获取有序集合的成员数 |
ZCOUNT |
计算在有序集合中指定区间分数的成员数 |
ZINCRBY |
有序集合中对指定成员的分数加上增量 increment |
ZINTERSTORE |
计算给定的一个或多个有序集的交集并将结果集存储在新的有序集合 key 中 |
ZLEXCOUNT |
在有序集合中计算指定字典区间内成员数量 |
ZRANGE |
通过索引区间返回有序集合成指定区间内的成员 |
ZRANGEBYLEX |
通过字典区间返回有序集合的成员 |
ZRANGEBYSCORE |
通过分数返回有序集合指定区间内的成员 |
ZRANK |
返回有序集合中指定成员的索引 |
ZREM |
移除有序集合中的一个或多个成员 |
ZREMRANGEBYLEX |
移除有序集合中给定的字典区间的所有成员 |
ZREMRANGEBYRANK |
移除有序集合中给定的排名区间的所有成员 |
ZREMRANGEBYSCORE |
移除有序集合中给定的分数区间的所有成员 |
ZREVRANGE |
返回有序集中指定区间内的成员,通过索引,分数从高到底 |
ZREVRANGEBYSCORE |
返回有序集中指定分数区间内的成员,分数从高到低排序 |
ZREVRANK |
返回有序集合中指定成员的排名,有序集成员按分数值递减(从大到小)排序 |
ZSCORE |
返回有序集中,成员的分数值 |
ZUNIONSTORE |
计算一个或多个有序集的并集,并存储在新的 key 中 |
ZSCAN |
迭代有序集合中的元素(包括元素成员和元素分值) |
5.3 操作例子
127.0.0.1:6379> zadd zskill 1 golang 2 rust 3 java 4 typescript 5 flutter
(integer) 5
127.0.0.1:6379> zcount zskill 1 3
(integer) 3
127.0.0.1:6379> zrange zskill 1 3 withscores
1) "rust"
2) "2"
3) "java"
4) "3"
5) "typescript"
6) "4"
127.0.0.1:6379> zrevrange zskill 1 3 withscores
1) "typescript"
2) "4"
3) "java"
4) "3"
5) "rust"
6) "2"