基本全局命令
generic命令通常指的是 generic key commands,也就是对 Key 本身进行操作的命令,这些命令和存储在 Key 里面的 Value 的具体类型没有关系。Key 永远只是一个字符串名字(String),Key 都支持的操作是通用的。
Redis有5种数据结构,但它们都是键值对中的值(毕竟Redis是键值对、非关系型数据库),对于键来说有一些通用命令,下面将介绍一下一些常用的对key使用的通用命令(generic key commands)。
KEYS
在介绍这个命令之前,为了方便理解,我们先简单介绍一下string数据结构中的set和get命令(具体细节看String的数据结构命令介绍)
我们可以通过set放入一个key拥有string类型的value值
例如:
set key1 12306我们同时可以通过get来得到key对应的value值
例如
get key 结果:12306
语法:
KEYS pattern
作用:Returns all keys matching pattern.
也就是说我们可以通过一些格式来返回所有key值只要其符合pattern的匹配对象。
注意:Redis 的 KEYS pattern 使用的是类似 Shell 通配符(glob pattern)的匹配规则,而不是正则表达式。(这里具体的Shell通配符匹配规则不细讲,网上都可以查询到)
时间复杂度:O(N)
返回值:所有被匹配到的key
例如:
127.0.0.1:6379> set hello 1
OK
127.0.0.1:6379> set hallo 2
OK
127.0.0.1:6379> set hollo 3
OK
127.0.0.1:6379> keys h[ae]llo
1) "hallo"
2) "hello"
EXISTS
语法:
EXISTS key [key ...]
作用:判断一个或多个key是否存在。
时间复杂度:O(N),N表示本次命令中需要判断的key的数量。当只判断一个key时,可以看作O(1)。
返回值:返回存在的key的数量,而不是简单地返回true或者false。
例如:
127.0.0.1:6379> set key1 12306
OK
127.0.0.1:6379> exists key1
(integer) 1
127.0.0.1:6379> exists key1 key2
(integer) 1
上面的key1存在,而key2不存在,因此返回1。如果两个key都存在,则返回2;如果两个key都不存在,则返回0。
注意:如果在一条命令中重复传入同一个存在的key,那么这个key会被重复计算。
127.0.0.1:6379> exists key1 key1
(integer) 2
为什么通常使用EXISTS key1 key2,而不是分别执行两次EXISTS?
Redis是由客户端和服务端构成的。我们在代码中调用Redis命令时,命令并不是直接在客户端本地完成的,而是通常需要经过下面的过程:
- 客户端将命令按照Redis通信协议编码,然后通过网络发送给Redis服务端;
- Redis服务端接收并执行命令;
- Redis服务端将执行结果通过网络返回给客户端;
- 客户端接收并解析结果。
如果分别执行下面两条命令:
EXISTS key1
EXISTS key2
在没有使用Pipeline(管道)的情况下,通常需要进行两次请求和两次响应,也就是两次网络往返。
而把它们合并成一条命令:
EXISTS key1 key2
客户端只需要发送一次请求,Redis也只需要返回一次响应,因此只发生一次网络往返。虽然Redis在服务端仍然需要依次判断两个key,服务端的时间复杂度仍然是O(N),但是它减少了网络往返次数、协议解析次数以及请求和响应的数据包开销。
在实际开发中,网络通信的耗时往往比Redis在内存中判断一个key是否存在的耗时更明显,毕竟网络也是IO嘛。因此,当我们只关心"一共有多少个key存在"时,通常应优先使用EXISTS key1 key2 ...,而不是把命令拆开执行。
不过,批量EXISTS只返回存在的key的总数,不能告诉我们具体是哪一个key存在。如果业务需要得到每一个key各自的判断结果,可以分别执行EXISTS并使用Pipeline一次性发送,从而在获得逐个结果的同时减少网络往返次数。
注意:命令参数之间使用空格分隔,正确写法是
EXISTS key1 key2,而不是EXISTS key1,key2。在Redis Cluster中,多key命令还会受到哈希槽的限制;如果key不在同一个哈希槽中,可能需要由客户端拆分请求,或者使用{}哈希标签让相关key落到同一个槽中。
DEL
语法:
DEL key [key ...]
作用:删除一个或多个key。不存在的key会被忽略,不会抛出错误。
时间复杂度:删除多个key时为O(N),N表示key的数量。对于String类型的值,删除单个key通常为O(1);如果值本身包含大量元素,例如很大的List、Set、ZSet或者Hash,释放值所占用的内存还可能产生额外耗时。
返回值:实际被删除的key的数量。
例如:
127.0.0.1:6379> set key1 12306
OK
127.0.0.1:6379> set key2 10086
OK
127.0.0.1:6379> del key1 key2 key3
(integer) 2
127.0.0.1:6379> exists key1 key2
(integer) 0
因为key1和key2存在,而key3不存在,所以实际删除了两个key,返回2。
如果需要删除很大的复杂类型key,又不希望释放内存的过程长时间阻塞Redis,可以了解一下UNLINK命令。UNLINK会先把key从键空间中移除,再由后台线程异步回收相应的内存。
EXPIRE
语法:
EXPIRE key seconds [NX | XX | GT | LT]
作用:为key设置以秒为单位的过期时间。当过期时间到达后,Redis会自动删除这个key。
时间复杂度:O(1)
返回值:
- 返回1:成功为key设置了过期时间。
- 返回0:key不存在,或者指定的条件没有满足。
例如:
127.0.0.1:6379> set code 1234
OK
127.0.0.1:6379> expire code 60
(integer) 1
127.0.0.1:6379> ttl code
(integer) 60
上面的命令表示让code在60秒后过期。
EXPIRE还支持下面几个条件选项:
NX:只有key当前没有过期时间时,才设置过期时间;XX:只有key当前已经有过期时间时,才更新过期时间;GT:只有新的过期时间大于当前过期时间时,才更新;LT:只有新的过期时间小于当前过期时间时,才更新。
例如:
127.0.0.1:6379> expire code 120 GT
(integer) 1
这表示只有新的120秒大于code当前剩余的过期时间时,才进行更新。
注意:
- 如果
seconds为0或者负数,key会被立即删除; - 使用
SET key value重新设置一个key时,通常会清除它原来的过期时间。如果希望保留原来的过期时间,可以使用SET命令的KEEPTTL选项; - 如果想使用毫秒作为单位,可以使用
PEXPIRE命令。
TTL
语法:
TTL key
作用:获取key剩余的生存时间,单位为秒。
时间复杂度:O(1)
返回值:
- 返回大于等于0的整数:key剩余的生存时间,单位为秒;
- 返回
-1:key存在,但是没有设置过期时间,也就是永久有效; - 返回
-2:key不存在。
例如:
127.0.0.1:6379> set key1 12306
OK
127.0.0.1:6379> ttl key1
(integer) -1
127.0.0.1:6379> expire key1 60
(integer) 1
127.0.0.1:6379> ttl key1
(integer) 60
127.0.0.1:6379> ttl not-exists-key
(integer) -2
由于命令执行和网络传输都会消耗一点时间,所以在实际环境中,设置60秒后再查询TTL时,也可能看到59等接近60的值,这是正常现象。
如果需要得到毫秒级的剩余生存时间,可以使用PTTL命令。
TYPE
语法:
TYPE key
作用:查看key对应的value是什么数据类型。
时间复杂度:O(1)
返回值:返回key对应的数据类型。常见结果包括:
string:字符串;list:列表;set:集合;zset:有序集合;hash:哈希;stream:流;none:key不存在。
例如:
127.0.0.1:6379> set key1 12306
OK
127.0.0.1:6379> type key1
string
127.0.0.1:6379> lpush names Tom Jack
(integer) 2
127.0.0.1:6379> type names
list
127.0.0.1:6379> type not-exists-key
none
TYPE命令只能告诉我们value的顶层数据类型,不能直接展示value中保存的具体内容。要读取具体内容,需要根据对应的数据类型使用GET、LRANGE、SMEMBERS、HGETALL等命令。