> 文章列表 > 【Redis14】Redis基础:通用命令(一)

【Redis14】Redis基础:通用命令(一)

【Redis14】Redis基础:通用命令(一)

Redis基础学习:通用命令(一)

我们已经学过了很多命令,但是有些通用命令是和具体的数据类型或者某些具体的功能无关的。它们主要是为一些通用功能提供的一些命令,就像是我们在业务开发的时候经常会写的那些通用函数一样。这些命令其实都比较简单,但是大部分同学可能还会有很多命令完全没用过。就像我一样,没有系统学习之前,我也真的只知道 GET 和 SET 。

KEYS

KEYS 命令应该还是比较入门的而且大家都经常会使用的一个命令。可以说是和 GET/SET 同级别的超常用命令,所以对于这个命令咱们也不过多介绍了。它支持正则匹配来查找 KEY 信息。

127.0.0.1:6379> keys *
1) "a"
2) "data"

具体支持的正则表达式模式包括:

  • h?llo 匹配 hellohallo 和 hxllo

  • h*llo 匹配 hllo 和 heeeello

  • h[ae]llo 匹配 hello 和 hallo, 但是不匹配 hillo

  • h[^e]llo 匹配 hallo, hbllo, … 但是不匹配 hello

  • h[a-b]llo 匹配 hallo 和 hbllo

KEYS 命令需要注意的一点是,它的查找时间复杂度为 O(N) ,N 为数据库里面 KEY 的数量,在一个有1百万个 KEY 的数据库里面执行一次查询需要的时间是40毫秒 。看起来很快吧?但是在一个大的数据库中使用它仍然可能造成性能问题,别问我怎么知道,哥们试过,太酸爽了。官方的建议是如果你需要从一个数据集中查找特定的 KEYS 可以使用 SCAN 或者 Sets 数据结构。

至于为什么不能在线上使用 KEYS * ,别忘了,Redis 是单线程的,KEYS * 如果耗时很长会阻塞其它命令。关于单线程的问题我们到进阶系列的时候再说。

是否存在

使用 EXISTS 命令可以判断一个 KEY 是否存在,它可以接收多个参数。

127.0.0.1:6379> EXISTS a1 a2 a3 a4
(integer) 2
127.0.0.1:6379> EXISTS a1
(integer) 1

复制

在 Redis6.2 之后,新提供了一个 COPY 命令,可以帮助我们快速方便地复制数据。

127.0.0.1:6379> COPY a a1
(integer) 1
127.0.0.1:6379> get a1
"111"

同时,它还提供了参数可以直接将数据复制到其它库中。

127.0.0.1:6379> COPY a a1 DB 1
(integer) 1
127.0.0.1:6379> select 1
OK
127.0.0.1:6379[1]> get a1
"111"

如果要复制到的 KEY 已经存在,那么 COPY 命令就不会直接覆盖,我们可以使用 REPLACE 参数强制替换。

127.0.0.1:6379> set b 222
OK
127.0.0.1:6379> COPY b a1
(integer) 0
127.0.0.1:6379> get a1
"111"
127.0.0.1:6379> COPY b a1 REPLACE
(integer) 1
127.0.0.1:6379> get a1
"222"

移动

有复制当然也会有移动啦,我们先来看一个跨服务器实例的移动,使用的是 MIGRATE ,这个命令其实更合适的叫法应该是 迁移 。

// 6379
127.0.0.1:6379> MIGRATE 127.0.0.1 6380 "" 1 3000 KEYS a
OK// 6380
➜  ~ redis-cli -p 6380
127.0.0.1:6380> get a
(nil)
127.0.0.1:6380> select 1
OK
127.0.0.1:6380[1]> get a
"111"// 6379
127.0.0.1:6379> get a
(nil)
127.0.0.1:6379> MIGRATE 127.0.0.1 6380 "" 1 3000 REPLACE KEYS a
NOKEY

在上面我们新开启了一个 6380 的服务端实例。然后通过 MIGRATE 命令将 a 这个 KEY 迁移到了 6380 的库中,原先 6379 中已经没有这个 KEY 了。它的参数比较多,大家可以自己去看一下,同样,它也支持 REPLACE 参数。

这么强大,那么我们可以在同一个实例内移动吗?

127.0.0.1:6379> MIGRATE 127.0.0.1 6379 "" 1 3000 REPLACE KEYS a
(error) IOERR error or timeout reading to target instance
(3.00s)
127.0.0.1:6379> select 1
OK
127.0.0.1:6379[1]> get a
"111"

上面的报错是超时 3s 后报的错,但其实数据复制到 1 库了,注意,是复制,默认的 0 库也在,1 库也会出现一条新的。但是这样很明显不是很好,毕竟我们在同一个服务端实例中移动数据完全用不着这么麻烦,只需要使用 MOVE 命令就好啦。

127.0.0.1:6379> set a 111
OK
127.0.0.1:6379> MOVE a 1
(integer) 1
127.0.0.1:6379> SELECT 1
OK
127.0.0.1:6379[1]> get a
"111"

MOVE 命令是没有 REPLACE 的,毕竟它不是复制替换,只是移动,如果目标库有相同的内容了,就无法移动。

127.0.0.1:6379[1]> SELECT 0
OK
127.0.0.1:6379> get a
(nil)
127.0.0.1:6379> set a 112
OK
127.0.0.1:6379> MOVE a 1
(integer) 0

MIGRATE 是一个原子命令,在迁移的时候会同时阻塞两个实例的操作,

序列化与反序列化

是的,你没看错,和 PHP 中的 serialize() 以及 unserialize() 一样,Redis 中也有序列化的功能,使用的命令是 DUMP 和 RESTORE 。

127.0.0.1:6379> DUMP a
"\\x00\\xc0o\\t\\x00\\x1f<t\\x0e\\xeb'\\x9cE"127.0.0.1:6379> RESTORE as1 0 "\\x00\\xc0o\\t\\x00\\x1f<t\\x0e\\xeb'\\x9cE"
OK127.0.0.1:6379> get as1
"111"

对于 DUMP 来说,没有别的什么参数,它的唯一作用就是将指定的 KEY 数据转化成序列化的内容。而 RESTORE 则更复杂一些,包含更多的参数。

RESTORE key ttl serialized-value [REPLACE] [ABSTTL] [IDLETIME seconds] [FREQ frequency]

如果在 RESTORE 中指定的 KEY 是已经存在的,那么也需要使用 REPLACE 进行覆盖替换。同时,它对于中文的支持也是没问题的。

127.0.0.1:6379> set a "ask 123 您"
OK
127.0.0.1:6379> DUMP a
"\\x00\\x0bask 123 \\xe6\\x82\\xa8\\t\\x00\\xce\\xa1\\x81D*\\xce\\xbc<"127.0.0.1:6379> RESTORE as1 0 "\\x00\\x06ask\\xe4\\xb8\\xad\\t\\x00\\xbe\\xf4I\\xb5\\x1f\\xe0\\xbb\\xa9"
(error) BUSYKEY Target key name already exists.
127.0.0.1:6379>  RESTORE as1 0 "\\x00\\x0bask 123 \\xe6\\x82\\xa8\\t\\x00\\xce\\xa1\\x81D*\\xce\\xbc<" REPLACE
OK127.0.0.1:6379> get as1
"ask 123 \\xe6\\x82\\xa8"

前面我们学习过的 MIGRATE 在传输过程中,其实就是通过序列化的方式来传输数据的。另外编码的结果还包括这些特点:

  • 它带有 64 位的校验和,用于检测错误,RESTORE 在进行反序列化之前会先检查校验和。

  • 值的编码格式和 RDB 文件保持一致。

  • RDB 版本会被编码在序列化值当中,如果因为 Redis 的版本不同造成 RDB 格式不兼容,那么 Redis 会拒绝对这个值进行反序列化操作。

时间相关操作

对于时间的处理,其实在最早的时候学习 String 相关操作时就有说过一点,因为现在 SET 命令已经包含很多选项并且可以直接设置时间了。但是对于其它数据类型,还是需要使用传统的 EXPIRE 相关命令来进行时间设置的。同时,TTL 命令应该也是大家非常熟悉的,这个命令返回还有多久时间会过期。

127.0.0.1:6379> EXPIRE a 20
(integer) 1127.0.0.1:6379> TTL a
(integer) 15
127.0.0.1:6379> TTL a
(integer) 12// 等20秒后
127.0.0.1:6379> TTL a
(integer) -2

消除过期时间

对于一个有过期时间的 KEY 来说,如果我们想要消除它的过期时间,可以使用 PERSIST 命令。

127.0.0.1:6379> SET a 123
OK
127.0.0.1:6379> EXPIRE a 20
(integer) 1
127.0.0.1:6379> TTL a
(integer) 18
127.0.0.1:6379> PERSIST a
(integer) 1
127.0.0.1:6379> TTL a
(integer) -1

除了这个命令还有什么方式呢?其实我们也可以直接再 SET 一次这个 KEY 。

127.0.0.1:6379> set a 111
OK
127.0.0.1:6379> ttl a
(integer) -1

指定时间过期

通过 EXPIREAT 命令,可以指定一个固定的时间戳,然后 KEY 会在这个时间后过期。

// 2025-05-30 17:25:01
127.0.0.1:6379> EXPIREAT a 1748597101
(integer) 1
127.0.0.1:6379> TTL a
(integer) 94694369
127.0.0.1:6379> TTL a
(integer) 94694367

毫秒操作

上面的几个命令都是秒级的操作,Redis 同时还支持毫秒级的操作,命令都只是在秒级命令前面加了个 P ,比如 PEXPIRE、PTTL、PEXPIREAT 。

127.0.0.1:6379> PEXPIRE a 500000
(integer) 1
127.0.0.1:6379> TTL a
(integer) 497
127.0.0.1:6379> PTTL a
(integer) 492449127.0.0.1:6379> PEXPIREAT a 1748597101000
(integer) 1
127.0.0.1:6379> TTL a
(integer) 94694135
127.0.0.1:6379> PTTL a
(integer) 94694129803

最新的 Redis7 新增加了 EXPIRETIME 和 PEXPIRETIME 命令,我这里还没有升级,所以就不演示了。它的作用是返回指定的 KEY 具体在哪一个时间点会过期,TTL 返回的是倒数的秒数,而 EXPIRETIME 返回的是到期时间的时间戳。

随机返回一个 KEY

从所有的 KEY 中,随机的返回一个 KEY ,这个操作是相当快的,可以达到 O(1) ,使用的是 RANDOMKEY 这个命令。

127.0.0.1:6379> keys *
1) "a2"
2) "d"
3) "e"
4) "c"
5) "b"
6) "data"
7) "a"
8) "a1"
9) "as1"
127.0.0.1:6379> RANDOMKEY
"a2"

修改 KEY 名称

想要修改一个 KEY 的名称,可以使用 RENAME 命令,指定原来的 KEY 和想要修改成的名称就可以了。

127.0.0.1:6379> RENAME a1 a111
OK
127.0.0.1:6379> KEYS *
1) "a2"
2) "d"
3) "e"
4) "c"
5) "b"
6) "data"
7) "a"
8) "a111"
9) "as1"

如果新的名称已经存在了,那么会直接覆盖,如果源名称的 KEY 不存在了,自然也就直接会报错。

127.0.0.1:6379> set a 555
OK
127.0.0.1:6379> RENAME a a111
OK
127.0.0.1:6379> get a111
"555"127.0.0.1:6379> RENAME a2 a222
OK
127.0.0.1:6379> KEYS *
1) "d"
2) "e"
3) "a222"
4) "c"
5) "b"
6) "data"
7) "a"
8) "a111"
9) "as1"
127.0.0.1:6379> RENAMENX a2 a222
(error) ERR no such key

SCAN

最后就是上面说过的一个问题,KEYS * 的执行速度慢,在单线程程序中会影响到后面命令的执行。其中官方第一个推荐的就是使用 SCAN 。

关于 SCAN 的内容之前在学习 Hash、Set、Sorted Set 时就已经学习过了,HSCAN、SSCAN 以及 ZSCAN 分别就是对应上述三种数据类型的迭代命令。而不带任何前缀的 SCAN 命令就是用来迭代所有的 KEY 信息的。

127.0.0.1:6379> scan 0
1) "0"
2) 1) "d"2) "e"3) "a"4) "c"5) "data"6) "a222"7) "b"8) "a111"9) "as1"

详细的测试就不演示了,大家可以使用外部程序多创建一些 KEY 就可以体现出 SCAN 的强大了。其它的用法以及参数作用和我们之前学习过的那些 HSCAN 之类的都一样。

总结

通用命令的第一部分就是这些,命令都比较简单,但说实话可能很多同学包括我,除了 EXPIRE 和 KEYS 就没用过别的了。没关系,起码现在咱们都知道了 COPY、MOVE 命令,也知道了 Redis 中也有序列化操作了吧。下一篇还是基础通用命令的部分,大家加油,整个基础部分的学习就快要结束了哦!