Redis命令
时间:2023-05-06 00:07:00
Redis相关API
Redis 命令参考:http://redisdoc.com
一、Redis底层
1、redis数据类型
类型 | 底层 | 应用场景 | 编码类型(数据量由大到小) |
---|---|---|---|
String | SDS数组 | 帖子、评论、热点数据输入缓冲 | RAW << EMBSTR << INT |
List | QuickList | 评论列表、商品列表、发布和订阅、慢查询、监视器 | LINKEDLIST << ZIPLIST |
Set | intSet | 适用于交集、并集、收集等朋友关系 | HT << INSET |
Zset | 跳跃表 | 重新排序适合排名场景 | SKIPLIST << ZIPLIST |
Hash | 哈希 | 存储对象等结构化数据 | HT << ZIPLIST |
Stream | 紧凑列表 | 消息队列 |
2、redis底层数据结构
1)SDS数组结构(简单动态字符串)用于存储字符串、整形数据和输入缓冲。
struct sdshdr{
int len;//记录buf在数组中使用字节的数量 int free; //记录 buf 未使用字节的数量在数组中 char buf[];//字符数组,用于保存字符串 }
2)跳跃表:将有序链表中的部分节点分层,每一层都是一个有序链表。
1.可以快速找到所需的节点 O(logn) ,额外存储空间的两倍
2、可以在O(1)在时间复杂度下,快速获得跳跃表的头节点、尾节点、长度和高度。
3)字典dict: 又称散列表(hash),用于存储键值对的数据结构。
Redis整个数据库存储在字典中(K-V结构) —Hash 数组 链表
Redis字典实现包括:字典(dict)、Hash表(dictht)、Hash表节点(dictEntry)。
字典达到存储上限(阈值) 0.75),需要rehash(扩容)
1.首次申请的默认容量为4dictEntry,非初次申请为当前hash表容量的两倍。
2、rehashidx=0表示要进行rehash操作。
3.新增数据在新增hash表h[1] 、修改、删除、查询老年人hash表h[0]
4、将老的hash表h重新计算索引值后,所有数据都迁移到新的hash表h这个过程在[1]中被称为 rehash。
渐进式rehash
当数据量巨大时rehash过程很慢,需要优化。 根据服务器的空闲程度,可以批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批量批rehash部分节点
4)压缩列表zipList
压缩列表(ziplist)顺序数据结构由一系列特殊编码的连续内存块组成,节省内容
sorted-set和hash元素个数少而且是小整数或短字符串(直接使用)
list用快速链表(quicklist)而数据结构存储快速链表是双向列表和压缩列表组合。(间接使用)
5)整数集合intSet
整数集合(intset)连续存储结构有序(整数升序)和存储整数。
当Redis集合元素均为整数,均在64位符号整数范围内(2^64),使用该结构体存储。
6)快速列表quickList
快速列表(quicklist)是Redis重要的底层数据结构。Redis3.2列表底层实现。
(在Redis3.2之前,Redis采用双向链表(adlist)和压缩列表(ziplist)实现)
7)Redis Stream主要使用底层listpack(紧凑列表)和Rax树(基数树)。
listpack表示字符串列表的序列化,listpack可用于存储字符串或整数。用于存储stream消息内容。
Rax树是有序字典树 (基数树 Radix Tree),按照 key 支持快速定位、插入和删除字典序列。
3、Zset底层实现
跳表(skip List)它是一种基于并联链表的随机数据结构,实现简单、插入、删除和搜索的复杂性O(logN)。简单来说,跳表也是一种链表,但它在链表的基础上增加了跳跃功能。正是这种跳跃功能使跳表能够在搜索元素时提供O(logN)时间复杂
Zset当数据量少时,使用压缩链表ziplist实现,有序集合使用压缩列表节点保存在一起,第一个节点保存member,第二个保存score。ziplist按下内部的集合元素score从小到大,score较小的位于表头。 当数据量大时,使用跳跃列表skiplist和哈希表hash_map结合实现,搜索和删除插入的时间复杂性是O(longN)
Redis由于跳表的索引结构序列化和反序列化更快,使用跳表而不是红黑树,方便持久化。
搜索
跳跃表按 score 从小到大保存所有集合元素,平均搜索时间复杂度 O(logN),最坏 O(N) 。
插入
选用链表作为底层结构支持,为了高效地动态增删。因为跳表底层的单链表是有序的,为了维护这种有序性,在插入前需要遍历链表,找到该插入的位置,单链表遍历查找的时间复杂度是O(n),同样,跳表的遍历也需要遍历索引数,所以是O(logn)。
删除
如果节点仍在索引中,不仅要删除单链表中的节点,还要删除索引中的节点;当单链表知道删除的节点是谁时,时间的复杂性是O(1)但对于单链表,删除时需要获得前驱节点O(logN)目标节点可以通过改变引用关系来删除。
4、编码类型
[外链图片转存失败,源站可能有防盗链机制,建议保存图片并直接上传(img-jQVD8kGn-1625484805976)(C:\Users\AdministratorGUET\AppData\Roaming\Typora\typora-user-images\image-20210503133758497.png)]
-
字符串对象
-
字符串编码
字符串对象的编码可以是int、raw或者embstr。
1)如果保存了字符串对象整数值,并且这个整数值可以用lon类型表示,那么字符串对象将整数值保存在字符串对象结构的ptr属性里面(将void*转换成long),并将字符串对象的编码方式设置为int。
2)如果字符串对象保存的是一个字符串值,并且这个字符串值的长度大于32字节,那么字符串对象将使用一个简单动态字符串保存这个值,并将对象的编码设置为raw。
3)如果字符串对象保存的是一个字符串值,并且这个字符串值的长度小于32字节,那么字符串对象将使用embstr编码的方式来保存这个字符串值。
-
编码的转换
int编码和embstr编码的字符串对象在满足条件的情况下,会转换为raw编码的字符串对象。
1)int编码转为raw编码:原对象保存的值不再是整数值,而是一个字符串值,那么会发生编码从int变为raw 2)redis没有为embstr编码的字符串对象编写任何相应的修改程序(只有int转为raw),所以,embstr编码字符串实际上是只读的,当对embstr编码的字符从执行修改命令时, 程序会先将对象的embstr转换成raw,然后再执行修改命令。(embstr编码的字符串对象执行APPEND命令后,对象的编码会从embstr变为raw)。
-
-
列表对象
-
列表对象的编码
列表对象的编码可以是ziplist或者linkedlist。ziplist编码的列表对象使用压缩列表作为底层实现,每个压缩列表节点保存一个列表节点。linkedlist编码的列表对象使用双端链表作为底层
实现。每个双端链表节点(node)都保存一个字符串对象,而每个字符串对象都保存了一个列表元素。
-
编码的转换
**当列表对象可以同时满足一下两个条件时,列表对象使用ziplist编码,**不能满足这两个条件的列表对象需要使用linkedlist编码。
1)列表对象保存的所有字符串元素的长度都小于64字节
2)列表对象保存的元素数量小于512个,
-
-
哈希对象
-
哈希对象的编码
哈希对象的编码可以是ziplist或者hashtable。
1)ziplist编码的哈希对象使用压缩列表作为底层实现,每当有新的键值对要加入到哈希对象时,程序会先将保存了键的压缩列表节点推入到压缩列表表尾,然后再将保存了值的压缩列表节点推入压缩列表表尾。因此
1、保存了同一键值对的两个节点总是紧挨在一起,保存键的节点在前,保存值的节点在后;
2、先添加到哈希对象中的键值对会放在压缩列表的表头方向,而后添加的哈希对象中的键值对会被放在压缩列表的链表方向。
2)hashtable编码的哈希对象使用字典作为底层实现,哈希对象中的每个键值对都使用一个字典键值对来保存
1、字典的每个键都是一个字符串对象,对象中保存了键值对的键。
2、字典中每个值都是一个字符串对象,对象中保存了键值对的值。
-
编码的转换
当哈希对象可以同时满足以下两个条件时,哈希对象使用ziplist编码,否则使用hashtable编码
1)哈希对象保存的所有键值对的键和值的字符串长度都小于64个字节
2)哈希对象保存的键值对数量小于512个
-
-
集合对象
-
集合对象的编码
集合对象的编码可以时intset或者hashtable
1)intset编码的集合对象使用整数集合作为底层实现,集合对象包含的所有元素都被保存在整数集合里面。
2)hashtable编码的集合对象使用字典作为底层实现,字典的每个键都是一个字符串对象,每个字符串对象都包含一个集合元素,而字典的值则被全部设置为NULL。
-
编码的转换
同时满足两个条件使用intset,否则使用hashtable
1)集合对象保存的所有值都是整数值 2)集合对象保存的元素数量不超过512个
-
-
有序集合对象
-
有序集合对象的编码
有序集合对象的编码可以时ziplist或者skiplist
1)ziplist编码的压缩列表对象使用压缩列表作为底层实现,每个集合元素使用两个紧挨在一起的压缩列表节点来保存,第一个节点保存元素的成员(member),第二个元素保存元素的分值(score)
压缩列表内的集合元素按照分值从小到大进行排序,分值较小的元素被放置在靠近表头的方向,而分值较大的元素则放置在靠近表尾的方向。
2)skiplist编码的有序集合对象使用zset结构作为底层实现,一个zset结构同时包含一个字典和一个跳跃表。
1、zset结构中的zsl跳跃表按分值从小到大保存了所有集合元素,每个跳跃表节点都保存一个集合元素:跳跃表即诶单 的object属性保存了元素成员,而跳跃表节点的score属性则保存了元素的分值。
通过跳跃表,程序可以对有序集合进行范围型操作,比如ZRANK、ZRANGE等命令就是基于跳跃表API来实现的
2、 zset结构中的dict字典为有序集合创建了一个从成员到分值的映射,字典中的每个键值对都保存了一个集合元素: 字典的键保存了元素的成员,而字典的值则保存了元素的分值。通过字典,程序
可以用O(1)复杂度查找给定成员的分值,ZSCORE命令就是根据这一特性是实现的。
-
编码的转换
同时满足一下两个条件使用ziplist,否则使用skiplist
1)有序集合所保存的所有元素成员的长度都小于64字节 2)有序集合保存的元素数量小于128个
-
5、管道(Pipeline)
管道字面意思就是流水线,它能将一组Redis命令进行组装,通过一次传输给Redis并返回结果集。类似于mget、mset这样的批处理命令,用于解决某些操作根本就不支持或没有批量操作的情况。
由于只有一次传输,Pipeline的性能比非Pipeline要好,尤其是网络延迟高的情况下。
批量命令、Pipeline 对比
- 原生批量命令是原子的,Pipeline 是非原子的。
- 原生批量命令是一个命令对应多个 key,Pipeline 支持多个命令。
- 原生批量命令是 Redis 服务端支持实现的,而 Pipeline 需要服务端和客户端的共同实现
适用场景
Peline
是 Redis 的一个提高吞吐量的机制,适用于多 key 读写场景,比如同时读取多个key
的value
,或者更新多个key
的value
,并且允许一定比例的写入失败、实时性也没那么高,那么这种场景就可以使用了。比如 10000 条一下进入 redis,可能失败了 2 条无所谓,后期有补偿机制就行了,像短信群发这种场景,这时候用 pipeline 最好了。
注意点
Pipeline
是非原子的,在上面原理解析那里已经说了就是 Redis 实际上还是一条一条的执行的,而执行命令是需要排队执行的,所以就会出现原子性问题。Pipeline
中包含的命令不要包含过多。Pipeline
每次只能作用在一个 Redis 节点上。Pipeline
不支持事务,因为命令是一条一条执行的。
二、Redis命令详解
相关API
http://redisdoc.com
类型 | |||||||||
---|---|---|---|---|---|---|---|---|---|
String | SET | SETNX | SETEX | GET | GETSET | INCR | DECR | MSET | MGET |
Hash | HSET | HSETNX | HGET | HDEL | HLEN | HMSET | HMGET | HKEYS | HGETALL |
LIST | LPUSH | LPOP | RPUSH | RPOP | LINDEX | LREM | LRANGE | LLEN | RPOPLPUSH |
ZSET | ZADD | ZREM | ZSCORE | ZCARD | ZRANGE | ZRANK | ZREVRANK | ZREVRANGE | |
SET | SADD | SREM | SISMEMBER | SCARD | SINTER | SUNION | SDIFF | SPOP | SMEMBERS |
事务 | MULTI | EXEC | DISCARD | WATCH | UNWATCH |
1、字符串(String)
SET
-
语法:SET key value [EX seconds] [PX milliseconds] [NX|XX]
将字符串值
value
关联到key
。如果
key
已经持有其他值,SET
就覆写旧值, 无视类型。当
SET
命令对一个带有生存时间(TTL)的键进行设置之后, 该键原有的 TTL 将被清除。 -
可选参数
EX seconds
: 将键的过期时间设置为seconds
秒。 执行SET key value EX seconds
的效果等同于执行SETEX key seconds value
。PX milliseconds
: 将键的过期时间设置为milliseconds
毫秒。 执行SET key value PX milliseconds
的效果等同于执行PSETEX key milliseconds value
。NX
: 只在键不存在时, 才对键进行设置操作。 执行SET key value NX
的效果等同于执行SETNX key value
。XX
: 只在键已经存在时, 才对键进行设置操作。
-
返回值
- 在 Redis 2.6.12 版本以前,
SET
命令总是返回OK
。 - 从 Redis 2.6.12 版本开始,
SET
命令只在设置操作成功完成时才返回OK
; 如果命令使用了NX
或者XX
选项, 但是因为条件没达到而造成设置操作未执行, 那么命令将返回空批量回复(NULL Bulk Reply)。
- 在 Redis 2.6.12 版本以前,
-
代码示例
对不存在的键进行设置:
redis> SET key "value" OK redis> GET key "value"
对已存在的键进行设置:
redis> SET key "new-value" OK redis> GET key "new-value"
使用
EX
选项:redis> SET key-with-expire-time "hello" EX 10086 // 单位是秒 OK redis> GET key-with-expire-time "hello" redis> TTL key-with-expire-time//查看剩余过期时间 (integer) 10069
使用
PX
选项:redis> SET key-with-pexpire-time "moto" PX 123321 // 单位是毫秒 OK redis> GET key-with-pexpire-time "moto" redis> PTTL key-with-pexpire-time (integer) 111939
使用
NX
选项:redis> SET not-exists-key "value" NX OK # 键不存在,设置成功 redis> GET not-exists-key "value" redis> SET not-exists-key "new-value" NX (nil) # 键已经存在,设置失败 redis> GET not-exists-key "value" # 维持原值不变
使用
XX
选项:redis> EXISTS exists-key (integer) 0 redis> SET exists-key "value" XX (nil) # 因为键不存在,设置失败 redis> SET exists-key "value" OK # 先给键设置一个值 redis> SET exists-key "new-value" XX OK # 设置新值成功 redis> GET exists-key "new-value"
SETNX
-
语法:SETNX key value
只在键
key
不存在的情况下, 将键key
的值设置为value
。若键
key
已经存在, 则SETNX
命令不做任何动作。SETNX
是『SET if Not EXists』(如果不存在,则 SET)的简写。 -
可选参数
-
返回值
命令在设置成功时返回
1
, 设置失败时返回0
。 -
代码示例
redis> EXISTS job # job 不存在 (integer) 0 redis> SETNX job "programmer" # job 设置成功 (integer) 1 redis> SETNX job "code-farmer" # 尝试覆盖 job ,失败 (integer) 0 redis> GET job # 没有被覆盖 "programmer"
SETEX
-
语法:SETEX key seconds value
将键
key
的值设置为value
, 并将键key
的生存时间设置为seconds
秒钟。如果键
key
已经存在, 那么SETEX
命令将覆盖已有的值。SETEX
命令的效果和以下两个命令的效果类似:SET key value EXPIRE key seconds # 设置生存时间
SETEX
和这两个命令的不同之处在于SETEX
是一个原子(atomic)操作, 它可以在同一时间内完成设置值和设置过期时间这两个操作, 因此SETEX
命令在储存缓存的时候非常实用。 -
可选参数
-
返回值
命令在设置成功时返回
OK
。 当seconds
参数不合法时, 命令将返回一个错误。 -
代码示例
在键
key
不存在的情况下执行SETEX
:redis> SETEX cache_user_id 60 10086 OK redis> GET cache_user_id # 值 "10086" redis> TTL cache_user_id # 剩余生存时间 (integer) 49
键
key
已经存在, 使用SETEX
覆盖旧值:redis> SET cd "timeless" OK redis> SETEX cd 3000 "goodbye my love" OK redis> GET cd "goodbye my love" redis> TTL cd (integer) 2997
PSETEX
-
语法:PSETEX key milliseconds value
可用版本: >= 2.6.0
时间复杂度: O(1)
这个命令和
SETEX
命令相似, 但它以毫秒为单位设置key
的生存时间, 而不是像SETEX
命令那样以秒为单位进行设置。 -
返回值
命令在设置成功时返回
OK
。 -
代码示例
redis> PSETEX mykey 1000 "Hello" OK redis> PTTL mykey //获取毫秒级过期时间 (integer) 999 redis> GET mykey "Hello"
GET
-
语法:GET key
返回与
key
相关联的字符串值。 -
可选参数
-
返回值
- 如果键
key
不存在, 那么返回特殊值nil
; 否则, 返回键key
的值。 - 如果键
key
的值并非字符串类型, 那么返回一个错误, 因为GET
命令只能用于字符串值。
- 如果键
-
代码示例
对不存在的键
key
或是字符串类型的键key
执行GET
命令:redis> GET db (nil) redis> SET db redis OK redis> GET db "redis"
对不是字符串类型的键
key
执行GET
命令:redis> DEL db (integer) 1 redis> LPUSH db redis mongodb mysql (integer) 3 redis> GET db (error) ERR Operation against a key holding the wrong kind of value
GETSET
-
语法:GETSET key value
可用版本: >= 1.0.0
时间复杂度: O(1)
将键
key
的值设为value
, 并返回键key
在被设置之前的旧值。 -
返回值
返回给定键
key
的旧值。如果键
key
没有旧值, 也即是说, 键key
在被设置之前并不存在, 那么命令返回nil
。当键
key
存在但不是字符串类型时, 命令返回一个错误。 -
代码示例
redis> GETSET db mongodb # 没有旧值,返回 nil (nil) redis> GET db "mongodb" redis> GETSET db redis # 返回旧值 mongodb "mongodb" redis> GET db "redis"
STRLEN
-
语法:STRLEN key
可用版本: >= 2.2.0
复杂度: O(1)
返回键
key
储存的字符串值的长度。 -
返回值
STRLEN
命令返回字符串值的长度。当键
key
不存在时, 命令返回0
。当
key
储存的不是字符串值时, 返回一个错误。 -
代码示例
获取字符串值的长度:
redis> SET mykey "Hello world" OK redis> STRLEN mykey (integer) 11
不存在的键的长度为
0
:redis> STRLEN nonexisting (integer) 0
APPEND
-
语法:APPEND key value
可用版本: >= 2.0.0
时间复杂度: 平摊O(1)
如果键
key
已经存在并且它的值是一个字符串,APPEND
命令将把value
追加到键key
现有值的末尾。如果
key
不存在,APPEND
就简单地将键key
的值设为value
, 就像执行SET key value
一样。 -
返回值
追加
value
之后, 键key
的值的长度。 -
代码示例
对不存在的
key
执行APPEND
:redis> EXISTS myphone # 确保 myphone 不存在 (integer) 0 redis> APPEND myphone "nokia" # 对不存在的 key 进行 APPEND ,等同于 SET myphone "nokia" (integer) 5 # 字符长度
对已存在的字符串进行
APPEND
:redis> APPEND myphone " - 1110" # 长度从 5 个字符增加到 12 个字符 (integer) 12 redis> GET myphone "nokia - 1110"
SETRANGE
-
语法:SETRANGE key offset value
可用版本: >= 2.2.0
时间复杂度:对于长度较短的字符串,命令的平摊复杂度O(1);对于长度较大的字符串,命令的复杂度为 O(M) ,其中 M 为
value
的长度。从偏移量
offset
开始, 用value
参数覆写(overwrite)键key
储存的字符串值。不存在的键
key
当作空白字符串处理。SETRANGE
命令会确保字符串足够长以便将value
设置到指定的偏移量上, 如果键key
原来储存的字符串长度比偏移量小(比如字符串只有5
个字符长,但你设置的offset
是10
), 那么原字符和偏移量之间的空白将用零字节(zerobytes,"\x00"
)进行填充。因为 Redis 字符串的大小被限制在 512 兆(megabytes)以内, 所以用户能够使用的最大偏移量为 2^29-1(536870911) , 如果你需要使用比这更大的空间, 请使用多个
key
。Warning 当生成一个很长的字符串时, Redis 需要分配内存空间, 该操作有时候可能会造成服务器阻塞(block)。 在2010年出产的Macbook Pro上, 设置偏移量为 536870911(512MB 内存分配)将耗费约 300 毫秒, 设置偏移量为 134217728(128MB 内存分配)将耗费约 80 毫秒, 设置偏移量 33554432(32MB 内存分配)将耗费约 30 毫秒, 设置偏移量为 8388608(8MB 内存分配)将耗费约 8 毫秒。
-
返回值
SETRANGE
命令会返回被修改之后, 字符串值的长度。 -
代码示例
对非空字符串执行
SETRANGE
命令:redis> SET greeting "hello world" OK redis> SETRANGE greeting 6 "Redis" (integer) 11 redis> GET greeting "hello Redis"
对空字符串/不存在的键执行
SETRANGE
命令:redis> EXISTS empty_string (integer) 0 redis> SETRANGE empty_string 5 "Redis!" # 对不存在的 key 使用 SETRANGE (integer) 11 redis> GET empty_string # 空白处被"\x00"填充 "\x00\x00\x00\x00\x00Redis!"
GETRANGE
-
语法:GETRANGE key start end
可用版本: >= 2.4.0
时间复杂度: O(N),其中 N 为被返回的字符串的长度。
返回键
key
储存的字符串值的指定部分, 字符串的截取范围由start
和end
两个偏移量决定 (包括start
和end
在内)。负数偏移量表示从字符串的末尾开始计数,
-1
表示最后一个字符,-2
表示倒数第二个字符, 以此类推。GETRANGE
通过保证子字符串的值域(range)不超过实际字符串的值域来处理超出范围的值域请求。GETRANGE
命令在 Redis 2.0 之前的版本里面被称为SUBSTR
命令。Python客户端至今仍然使用substr()方法获取字串,但是在使用2.0以上版本的Redis,那么最好使用getrange()方法来获取字串。 -
返回值
GETRANGE
命令会返回字符串值的指定部分。 -
代码示例
redis> SET greeting "hello, my friend" OK redis> GETRANGE greeting 0 4 # 返回索引0-4的字符,包括4。 "hello" redis> GETRANGE greeting -1 -5 # 不支持回绕操作 "" redis> GETRANGE greeting -3 -1 # 负数索引 "end" redis> GETRANGE greeting 0 -1 # 从第一个到最后一个 "hello, my friend" redis> GETRANGE greeting 0 1008611 # 值域范围不超过实际字符串,超过部分自动被符略 "hello, my friend"
INCR
-
语法:INCR key
为键
key
储存的数字值加上一。如果键
key
不存在, 那么它的值会先被初始化为0
, 然后再执行INCR
命令。如果键
key
储存的值不能被解释为数字, 那么INCR
命令将返回一个错误。本操作的值限制在 64 位(bit)有符号数字表示之内。
INCR命令是一个针对字符串的操作。因为Redis并没有专用的整数类型,所以键key存储的值在执行INCR命令时会被解释为十进制64位有符号整数。
-
返回值
INCR
命令会返回键key
在执行加一操作之后的值。 -
示例
redis> SET page_view 20 OK redis> INCR page_view (integer) 21 redis> GET page_view # 数字值在 Redis 中以字符串的形式保存 "21"
INCRBY
-
语法:INCRBY key increment
为键
key
储存的数字值加上增量increment
。如果键
key
不存在, 那么键key
的值会先被初始化为0
, 然后再执行INCRBY
命令。如果键
key
储存的值不能被解释为数字, 那么INCRBY
命令将返回一个错误。本操作的值限制在 64 位(bit)有符号数字表示之内。
关于递增(increment) / 递减(decrement)操作的更多信息, 请参见
INCR
命令的文档。 -
返回值
在加上增量
increment
之后, 键key
当前的值。 -
示例
键存在,并且值为数字:
redis> SET rank 50 OK redis> INCRBY rank 20 (integer) 70 redis> GET rank "70"
键不存在:
redis> EXISTS counter (integer) 0 redis> INCRBY counter 30 (integer) 30 redis> GET counter "30"
键存在,但值无法被解释为数字:
redis> SET book "long long ago..." OK redis> INCRBY book 200 (error) ERR value is not an integer or out of range
INCRBYFLOAT
-
语法:
可用版本: >= 2.6.0
时间复杂度: O(1)
为键
key
储存的值加上浮点数增量increment
。如果键
key
不存在, 那么INCRBYFLOAT
会先将键key
的值设为0
, 然后再执行加法操作。如果命令执行成功, 那么键
key
的值会被更新为执行加法计算之后的新值, 并且新值会以字符串的形式返回给调用者。无论是键
key
的值还是增量increment
, 都可以使用像2.0e7
、3e5
、90e-2
那样的指数符号(exponential notation)来表示, 但是, 执行 INCRBYFLOAT 命令之后的值总是以同样的形式储存, 也即是, 它们总是由一个数字, 一个(可选的)小数点和一个任意长度的小数部分组成(比如3.14
、69.768
,诸如此类), 小数部分尾随的0
会被移除, 如果可能的话, 命令还会将浮点数转换为整数(比如3.0
会被保存成3
)。此外, 无论加法计算所得的浮点数的实际精度有多长,
INCRBYFLOAT
命令的计算结果最多只保留小数点的后十七位。当以下任意一个条件发生时, 命令返回一个错误:
- 键
key
的值不是字符串类型(因为 Redis 中的数字和浮点数都以字符串的形式保存,所以它们都属于字符串类型); - 键
key
当前的值或者给定的增量increment
不能被解释(parse)为双精度浮点数。
- 键
-
返回值
在加上增量
increment
之后, 键key
的值。 -
代码示例
redis> GET decimal "3.0" redis> INCRBYFLOAT decimal 2.56 "5.56" redis> GET decimal "5.56"
DECR
-
语法:DECR key
可用版本: >= 1.0.0
时间复杂度: O(1)
为键
key
储存的数字值减去一。如果键
key
不存在, 那么键key
的值会先被初始化为0
, 然后再执行DECR
操作。如果键
key
储存的值不能被解释为数字, 那么DECR
命令将返回一个错误。本操作的值限制在 64 位(bit)有符号数字表示之内。
关于递增(increment) / 递减(decrement)操作的更多信息, 请参见
INCR
命令的文档。 -
返回值
DECR
命令会返回键key
在执行减一操作之后的值。 -
代码示例
对储存数字值的键
key
执行DECR
命令:redis> SET failure_times 10 OK redis> DECR failure_times (integer) 9
对不存在的键执行
DECR
命令:redis> EXISTS count (integer) 0 redis> DECR count (integer) -1
DECRBY
-
语法:DECRBY key decrement
可用版本: >= 1.0.0
时间复杂度: O(1)
将键
key
储存的整数值减去减量decrement
。如果键
key
不存在, 那么键key
的值会先被初始化为0
, 然后再执行DECRBY
命令。如果键
key
储存的值不能被解释为数字, 那么DECRBY
命令将返回一个错误。本操作的值限制在 64 位(bit)有符号数字表示之内。
关于更多递增(increment) / 递减(decrement)操作的更多信息, 请参见
INCR
命令的文档。 -
返回值
DECRBY
命令会返回键在执行减法操作之后的值。 -
代码示例
对已经存在的键执行
DECRBY
命令:redis> SET count 100 OK redis> DECRBY count 20 (integer) 80
对不存在的键执行
DECRBY
命令:redis> EXISTS pages (integer) 0 redis> DECRBY pages 10 (integer) -10
MSET
-
语法:MSET key value [key value …]
可用版本: >= 1.0.1
时间复杂度: O(N),其中 N 为被设置的键数量。
同时为多个键设置值。
如果某个给定键已经存在, 那么
MSET
将使用新值去覆盖旧值, 如果这不是你所希望的效果, 请考虑使用MSETNX
命令, 这个命令只会在所有给定键都不存在的情况下进行设置。MSET
是一个原子性(atomic)操作, 所有给定键都会在同一时间内被设置, 不会出现某些键被设置了但是另一些键没有被设置的情况。 -
返回值
MSET
命令总是返回OK
。 -
代码示例
同时对多个键进行设置:
redis> MSET date "2012.3.30" time "11:00 a.m." weather "sunny" OK redis> MGET date time weather 1) "2012.3.30" 2) "11:00 a.m." 3) "sunny"
覆盖已有的值:
redis> MGET k1 k2 1) "hello" 2) "world" redis> MSET k1 "good" k2 "bye" OK redis> MGET k1 k2 1) "good" 2) "bye"
MSETNX
-
语法:MSETNX key value [key value …]
可用版本: >= 1.0.1
时间复杂度: O(N), 其中 N 为被设置的键数量。
当且仅当所有给定键都不存在时, 为所有给定键设置值。
即使只有一个给定键已经存在,
MSETNX
命令也会拒绝执行对所有键的设置操作。MSETNX
是一个原子性(atomic)操作, 所有给定键要么就全部都被设置, 要么就全部都不设置, 不可能出现第三种状态。 -
返回值
当所有给定键都设置成功时, 命令返回
1
; 如果因为某个给定键已经存在而导致设置未能成功执行, 那么命令返回0
。 -
代码示例
对不存在的键执行
MSETNX
命令:redis> MSETNX rmdbs "MySQL" nosql "MongoDB" key-value-store "redis" (integer) 1 redis> MGET rmdbs nosql key-value-store 1) "MySQL" 2) "MongoDB" 3) "redis"
对某个已经存在的键进行设置:
redis> MSETNX rmdbs "Sqlite" language "python" # rmdbs 键已经存在,操作失败 (integer) 0 redis> EXISTS language # 因为 MSETNX 命令没有成功执行 (integer) 0 # 所以 language 键没有被设置 redis> GET rmdbs # rmdbs 键也没有被修改 "MySQL"
MGET
-
语法:MGET key [key …]
可用版本: >= 1.0.0
时间复杂度: O(N) ,其中 N 为给定键的数量。
返回给定的一个或多个字符串键的值。
如果给定的字符串键里面, 有某个键不存在, 那么这个键的值将以特殊值
nil
表示。 -
返回值
MGET
命令将返回一个列表, 列表中包含了所有给定键的值。 -
代码示例
redis> SET redis redis.com OK redis> SET mongodb mongodb.org OK redis> MGET redis mongodb 1) "redis.com" 2) "mongodb.org" redis> MGET redis mongodb mysql # 不存在的 mysql 返回 nil 1) "redis.com" 2) "mongodb.org" 3) (nil)
因为
SET
命令可以通过参数来实现SETNX
、SETEX
以及PSETEX
命令的效果, 所以 Redis 将来的版本可能会移除并废弃SETNX
、SETEX
和PSETEX
这三个命令。
2、哈希表(HASH)
HSET
-
语法:HSET hash field value
可用版本: >= 2.0.0
时间复杂度: O(1)
将哈希表
hash
中域field
的值设置为value
。如果给定的哈希表并不存在, 那么一个新的哈希表将被创建并执行
HSET
操作。如果域
field
已经存在于哈希表中, 那么它的旧值将被新值value
覆盖。 -
返回值
当
HSET
命令在哈希表中新创建field
域并成功为它设置值时, 命令返回1
; 如果域field
已经存在于哈希表, 并且HSET
命令成功使用新值覆盖了它的旧值, 那么命令返回0
。 -
代码示例
设置一个新域:
redis> HSET website google "www.g.cn" (integer) 1 redis> HGET website google "www.g.cn"
对一个已存在的域进行更新:
redis> HSET website google "www.google.com" (integer) 0 redis> HGET website google "www.google.com"
HSETNX
-
语法:HSETNX hash field value
可用版本: >= 2.0.0
时间复杂度: O(1)
当且仅当域
field
尚未存在于哈希表的情况下, 将它的值设置为value
。如果给定域已经存在于哈希表当中, 那么命令将放弃执行设置操作。
如果哈希表
hash
不存在, 那么一个新的哈希表将被创建并执行HSETNX
命令。 -
返回值
HSETNX
命令在设置成功时返回1
, 在给定域已经存在而放弃执行设置操作时返回0
。 -
代码示例
域尚未存在, 设置成功:
redis> HSETNX database key-value-store Redis (integer) 1 redis> HGET database key-value-store "Redis"
域已经存在, 设置未成功, 域原有的值未被改变:
redis> HSETNX database key-value-store Riak (integer) 0 redis> HGET database key-value-store "Redis"
HGET
-
语法:HGET hash field
可用版本: >= 2.0.0
时间复杂度: O(1)
返回哈希表中给定域的值。
-
返回值
HGET
命令在默认情况下返回给定域的值。如果给定域不存在于哈希表中, 又或者给定的哈希表并不存在, 那么命令返回
nil
。 -
代码示例
域存在的情况:
redis> HSET homepage redis redis.com (integer) 1 redis> HGET homepage redis "redis.com"
域不存在的情况:
redis> HGET site mysql (nil)
HEXISTS
-
语法:HEXISTS hash field
可用版本: >= 2.0.0
时间复杂度: O(1)
检查给定域
field
是否存在于哈希表hash
当中。 -
返回值
HEXISTS
命令在给定域存在时返回1
, 在给定域不存在时返回0
。 -
示例
给定域不存在:
redis> HEXISTS phone myphone (integer) 0
给定域存在:
redis> HSET phone myphone nokia-1110 (integer) 1 redis> HEXISTS phone myphone (integer) 1
HDEL
-
语法:HDEL key field [field …]
可用版本: >= 2.0.0
时间复杂度: O(N),N为要删除的域的数量。
删除哈希表key中的一个或者多个给定域,不存在的域将被忽略。
-
返回值
被成功移除的域的数量,不包括被忽略的域。
-
代码示例
# 测试数据 redis> HGETALL abbr 1) "a" 2) "apple" 3) "b" 4) "banana" 5) "c" 6) "cat" 7) "d" 8) "dog" # 删除单个域 redis> HDEL abbr a (integer) 1 # 删除不存在的域 redis> HDEL abbr not-exists-field (integer) 0 # 删除多个域 redis> HDEL abbr b c (integer) 2 redis> HGETALL abbr 1) "d" 2) "dog"
HLEN
-
语法:HLEN key
可用版本: >= 2.0.0
时间复杂度: O(1)。
返回哈希表
key
中域的数量。 -
返回值
哈希表中域的数量。
当key不存在的时候返回0。
-
代码示例
redis> HSET db redis redis.com (integer) 1 redis> HSET db mysql mysql.com (integer) 1 redis> HLEN db (integer) 2 redis> HSET db mongodb mongodb.org (integer) 1 redis> HLEN db (integer) 3
HSTRLEN
-
语法:HSTRLEN key field
返回哈希表
key
中,与给定域field
相关联的值的字符串长度(string length)。 -
返回值
返回哈希表
key
中,与给定域field
相关联的值的字符串长度(string length)。如果给定的键或者域不存在, 那么命令返回
0
。 -
代码示例
redis> HMSET myhash f1 "HelloWorld" f2 "99" f3 "-256" OK redis> HSTRLEN myhash f1 (integer) 10 redis> HSTRLEN myhash f2 (integer) 2 redis> HSTRLEN myhash f3 (integer) 4
HINCRBY
-
语法:HINCRBY key field increment
可用版本:>= 2.6.0
时间复杂度:O(1)
为哈希表key中的域field的值增加增量
increment
。增量也可以为负数,相当于对给定域进行减法操作。
如果
key
不存在,一个新的哈希表被创建并执行 HINCRBY 命令。如果域
field
不存在,那么在执行命令前,域的值被初始化为0
。对一个储存不是字符串值的域
field
执行 HINCRBY 命令将造成一个错误。本操作的值被限制在 64 位(bit)有符号数字表示之内。
-
返回值
执行 HINCRBY 命令之后,哈希表
key
中域field
的值。 -
代码示例
# increment 为正数 redis> HEXISTS counter page_view # 对空域进行设置 (integer) 0 redis> HINCRBY counter page_view 200 (integer) 200 redis> HGET counter page_view "200" # increment 为负数 redis> HGET counter page_view "200" redis> HINCRBY counter page_view -50 (integer) 150 redis> HGET counter page_view "150" # 尝试对字符串值的域执行HINCRBY命令 redis> HSET myhash string hello,world # 设定一个字符串值 (integer) 1 redis> HGET myhash string "hello,world" redis> HINCRBY myhash string 1 # 命令执行失败,错误。 (error) ERR hash value is not an integer redis> HGET myhash string # 原值不变 "hello,world"
HINCRBYFLOAT
-
语法:HINCRBYFLOAT key field increment
可用版本:>= 2.6.0
时间复杂度:O(1)
为哈希表
key
中的域field
加上浮点数增量increment
。如果哈希表中没有域
field
,那么 HINCRBYFLOAT 会先将域field
的值设为0
,然后再执行加法操作。如果键
key
不存在,那么 HINCRBYFLOAT 会先创建一个哈希表,再创建域field
,最后再执行加法操作。当以下任意一个条件发生时,返回一个错误:
- 域
field
的值不是字符串类型(因为 redis 中的数字和浮点数都以字符串的形式保存,所以它们都属于字符串类型) - 域
field
当前的值或给定的增量increment
不能解释(parse)为双精度浮点数(double precision floating point number)
HINCRBYFLOAT 命令的详细功能和 INCRBYFLOAT key increment 命令类似,请查看 INCRBYFLOAT key increment 命令获取更多相关信息。
- 域
-
返回值
执行加法操作之后
field
域的值。 -
代码示例
# 值和增量都是普通小数 redis> HSET mykey field 10.50 (integer) 1 redis> HINCRBYFLOAT mykey field 0.1 "10.6" # 值和增量都是指数符号 redis> HSET mykey field 5.0e3 (integer) 0 redis> HINCRBYFLOAT mykey field 2.0e2 "5200" # 对不存在的键执行 HINCRBYFLOAT redis> EXISTS price (integer) 0 redis> HINCRBYFLOAT price milk 3.5 "3.5" redis> HGETALL price 1) "milk" 2) "3.5" # 对不存在的域进行 HINCRBYFLOAT redis> HGETALL price 1) "milk" 2) "3.5" redis> HINCRBYFLOAT price coffee 4.5 # 新增 coffee 域 "4.5" redis> HGETALL price 1) "milk" 2) "3.5" 3) "coffee" 4) "4.5"
HMSET
-
语法:HMSET key field value [field value …]
可用版本:>= 2.0.0
时间复杂度:O(N),
N
为field-value
对的数量。同时将多个
field-value
(域-值)对设置到哈希表key
中。此命令会覆盖哈希表中已存在的域。
如果
key
不存在,一个空哈希表被创建并执行 HMSET 操作。 -
返回值
如果命令执行成功,返回
OK
。当
key
不是哈希表(hash)类型时,返回一个错误。 -
代码示例
redis> HMSET website google www.google.com yahoo www.yahoo.com OK redis> HGET website google "www.google.com" redis> HGET website yahoo "www.yahoo.com"
HMGET
-
语法:HMGET key field [field …]
可用版本:>= 2.0.0
时间复杂度:O(N),
N
为field-value
对的数量。返回哈希表
key
中,一个或多个给定域的值。如果给定的域不存在于哈希表,那么返回一个
nil
值。因为不存在的
key
被当作一个空哈希表来处理,所以对一个不存在的key
进行 HMGET 操作将返回一个只带有nil
值的表。 -
返回值
一个包含多个给定域的关联值的表,表值的排列顺序和给定域参数的请求顺序一样。
-
代码示例
redis> HMSET pet dog "doudou" cat "nounou" # 一次设置多个域 OK redis> HMGET pet dog cat fake_pet # 返回值的顺序和传入参数的顺序一样 1) "doudou" 2) "nounou" 3) (nil) # 不存在的域返回nil值
HKEYS
-
语法:HKEYS key
可用版本:>= 2.0.0
时间复杂度:O(N),
N
为 哈希表的大小。返回哈希表
key
中的所有域。 -
返回值
一个包含哈希表中所有域的表。
当
key
不存在时,返回一个空表。 -
代码示例
# 哈希表非空 redis> HMSET website google www.google.com yahoo www.yahoo.com OK redis> HKEYS website 1) "google" 2) "yahoo" # 空哈希表/key不存在 redis> EXISTS fake_key (integer) 0 redis> HKEYS fake_key (empty list or set)
HVALS
-
语法:HVALS key
可用版本:>= 2.0.0
时间复杂度:O(N),
N
为 哈希表的大小。返回哈希表
key
中所有