Redis 命令使用指南:从入门到实践
引言
Redis (Remote Dictionary Server) 是一个开源的、高性能的、基于内存的键值存储系统。它以其闪电般的速度、丰富的数据结构支持以及多样的应用场景(如缓存、消息队列、会话存储、排行榜、计数器等)而广受欢迎。要有效地利用 Redis 的强大功能,熟练掌握其命令是至关重要的。本指南旨在全面、详细地介绍 Redis 的常用命令,覆盖核心数据结构、键管理、服务器管理、事务、发布/订阅等多个方面,帮助开发者从入门到熟练运用 Redis。
一、连接与基础
1. 连接 Redis 服务器
通常使用 redis-cli
命令行工具连接到 Redis 服务器。
“`bash
连接本地默认端口 (6379)
redis-cli
连接指定主机和端口
redis-cli -h
连接需要密码认证的服务器
redis-cli -h
连接成功后,命令提示符会变为 hostname:port>
或 127.0.0.1:6379>
。
2. 基本概念
- 键 (Key): Redis 是键值存储,每个数据项都有一个唯一的键,键是字符串类型。良好的键命名规范对于维护大型 Redis 实例至关重要(例如:
object-type:id:field
->user:1001:profile
)。 - 值 (Value): Redis 的值可以是多种数据类型,包括字符串、列表、哈希、集合和有序集合。
- 数据库 (Database): Redis 默认支持 16 个数据库 (0-15)。可以使用
SELECT <db_index>
命令切换数据库。默认使用数据库 0。不同数据库之间的键空间是隔离的。
3. 常用服务器命令
PING
: 测试服务器是否仍在运行。如果服务器正常,返回PONG
。
127.0.0.1:6379> PING
PONGECHO <message>
: 回显指定的消息。
127.0.0.1:6379> ECHO "Hello Redis"
"Hello Redis"SELECT <index>
: 切换到指定的数据库。
127.0.0.1:6379> SELECT 1
OK
127.0.0.1:6379[1]> # 提示符显示当前数据库索引QUIT
: 关闭当前连接。AUTH <password>
: 如果服务器设置了密码,使用此命令进行认证。INFO [section]
: 获取 Redis 服务器的详细信息和统计数据。可以指定section
(如server
,clients
,memory
,persistence
,stats
,replication
,cpu
,commandstats
,cluster
,keyspace
)获取特定部分的信息。
127.0.0.1:6379> INFO memory
# Memory
used_memory:1040496
used_memory_human:1016.11K
...
二、键 (Key) 管理命令
这些命令用于管理 Redis 中的键,与值的类型无关。
KEYS <pattern>
: 查找所有符合给定模式pattern
的键。注意:KEYS
命令会遍历所有键,在生产环境中的大型数据库上使用可能会阻塞服务器,应谨慎使用或使用SCAN
替代。*
: 匹配任意数量的任意字符 (e.g.,KEYS user:*
)?
: 匹配单个任意字符 (e.g.,KEYS u?er:1
)[]
: 匹配方括号内的任意一个字符 (e.g.,KEYS user:[12]00
)
127.0.0.1:6379> SET user:1 "Alice"
OK
127.0.0.1:6379> SET user:2 "Bob"
OK
127.0.0.1:6379> KEYS user:*
1) "user:1"
2) "user:2"
SCAN <cursor> [MATCH <pattern>] [COUNT <count>]
: 增量迭代当前数据库中的键集合。它返回一个游标和一批键。每次调用使用上次返回的游标作为参数,直到游标返回 0 表示迭代完成。MATCH
用于过滤键名,COUNT
提示每次迭代返回的元素数量(但不保证精确)。这是在生产环境中替代KEYS
的推荐方式。
127.0.0.1:6379> SCAN 0 MATCH user:* COUNT 1
1) "12" # 新的游标
2) 1) "user:1"
127.0.0.1:6379> SCAN 12 MATCH user:* COUNT 1
1) "0" # 游标为 0,迭代结束
2) 1) "user:2"EXISTS <key> [key ...]
: 检查一个或多个键是否存在。返回存在的键的数量。
127.0.0.1:6379> EXISTS user:1 non_existing_key
(integer) 1DEL <key> [key ...]
: 删除一个或多个键。返回成功删除的键的数量。
127.0.0.1:6379> DEL user:1 user:2
(integer) 2UNLINK <key> [key ...]
: 异步删除键。它仅将键从键空间中移除,实际的内存回收在后台线程中进行。对于删除大型键(如包含数百万元素的列表或哈希)很有用,可以避免阻塞服务器。返回值与DEL
相同。TYPE <key>
: 返回键所存储的值的数据类型 (string
,list
,set
,zset
,hash
,stream
) 或none
(键不存在)。
127.0.0.1:6379> SET mykey "value"
OK
127.0.0.1:6379> TYPE mykey
stringRENAME <key> <newkey>
: 将键key
重命名为newkey
。如果newkey
已存在,其值将被覆盖。如果key
不存在,则返回错误。RENAMENX <key> <newkey>
: 仅当newkey
不存在时,将key
重命名为newkey
。成功返回 1,如果newkey
已存在则返回 0。EXPIRE <key> <seconds>
: 为键设置生存时间(秒)。到期后键会被自动删除。
127.0.0.1:6379> SET cache:page "<html>...</html>"
OK
127.0.0.1:6379> EXPIRE cache:page 60
(integer) 1 # 设置成功PEXPIRE <key> <milliseconds>
: 为键设置生存时间(毫秒)。EXPIREAT <key> <timestamp>
: 为键设置绝对过期时间(Unix 时间戳,秒)。PEXPIREAT <key> <milliseconds-timestamp>
: 为键设置绝对过期时间(Unix 时间戳,毫秒)。TTL <key>
: 以秒为单位,返回键的剩余生存时间。返回 -1 表示键永不过期,返回 -2 表示键不存在。
127.0.0.1:6379> TTL cache:page
(integer) 55 # 剩余 55 秒PTTL <key>
: 以毫秒为单位,返回键的剩余生存时间。PERSIST <key>
: 移除键的过期时间,使其永不过期。如果成功移除返回 1,如果键不存在或没有设置过期时间返回 0。RANDOMKEY
: 从当前数据库中随机返回一个键名。如果数据库为空,返回nil
。MOVE <key> <db>
: 将当前数据库的key
移动到指定的数据库db
。
三、字符串 (String) 类型命令
字符串是 Redis 最基本的数据类型,可以存储文本、序列化对象或二进制数据,最大可达 512MB。
SET <key> <value> [EX seconds] [PX milliseconds] [NX|XX]
- 设置键
key
的值为value
。 EX seconds
: 设置键的过期时间(秒)。等同于SET
+EXPIRE
。PX milliseconds
: 设置键的过期时间(毫秒)。等同于SET
+PEXPIRE
。NX
: 只在键不存在时才设置。用于实现锁或创建新记录。XX
: 只在键已存在时才设置。用于更新现有记录。
127.0.0.1:6379> SET user:100:name "Alice"
OK
127.0.0.1:6379> SET session:xyz "data" EX 3600 NX
OK # 如果 session:xyz 不存在,则设置成功并设置 1 小时过期
- 设置键
GET <key>
: 获取键key
的值。如果键不存在,返回nil
。
127.0.0.1:6379> GET user:100:name
"Alice"GETSET <key> <value>
: 设置键key
的新值value
,并返回键的旧值。如果键不存在,返回nil
。MSET <key> <value> [key value ...]
: 同时设置一个或多个键值对。原子操作。
127.0.0.1:6379> MSET product:1:name "Laptop" product:1:price 1200
OKMGET <key> [key ...]
: 获取一个或多个键的值。返回一个包含所有值的列表,对于不存在的键,对应位置返回nil
。
127.0.0.1:6379> MGET product:1:name product:1:price product:2:name
1) "Laptop"
2) "1200"
3) (nil)APPEND <key> <value>
: 如果键key
存在并且是字符串类型,将value
追加到其末尾。如果键不存在,则创建该键并设置其值,等同于SET
。返回追加后字符串的总长度。
127.0.0.1:6379> SET mylog "Event: "
OK
127.0.0.1:6379> APPEND mylog "User logged in. "
(integer) 26
127.0.0.1:6379> GET mylog
"Event: User logged in. "STRLEN <key>
: 返回键key
存储的字符串值的长度。如果键不存在,返回 0。INCR <key>
: 将键key
存储的数字值(必须是整数)加 1。如果键不存在,先初始化为 0 再执行加 1。返回加 1 后的值。原子操作,常用于计数器。
127.0.0.1:6379> SET counter 10
OK
127.0.0.1:6379> INCR counter
(integer) 11
127.0.0.1:6379> INCR non_exist_counter
(integer) 1INCRBY <key> <increment>
: 将键key
存储的数字值加上指定的增量increment
。返回增加后的值。DECR <key>
: 将键key
存储的数字值减 1。返回减 1 后的值。DECRBY <key> <decrement>
: 将键key
存储的数字值减去指定的减量decrement
。返回减少后的值。INCRBYFLOAT <key> <increment>
: 将键key
存储的数字值(可以是浮点数)加上指定的浮点数增量increment
。返回增加后的值(字符串形式)。SETRANGE <key> <offset> <value>
: 用value
覆盖键key
存储的字符串值,从偏移量offset
开始。返回修改后字符串的长度。GETRANGE <key> <start> <end>
: 获取键key
存储的字符串值的子字符串,由start
和end
偏移量(都包含)决定。支持负数偏移量(-1 表示最后一个字符)。
四、列表 (List) 类型命令
Redis 列表是简单的字符串列表,按照插入顺序排序。可以在列表的头部 (left) 或尾部 (right) 添加元素。列表底层实现是双向链表或压缩列表 (ziplist),插入和删除操作非常快。适合实现消息队列、最新动态等。
LPUSH <key> <element> [element ...]
: 将一个或多个元素插入到列表key
的头部(左侧)。返回插入后列表的长度。
127.0.0.1:6379> LPUSH mylist "world"
(integer) 1
127.0.0.1:6379> LPUSH mylist "hello"
(integer) 2
# 列表现在是 ["hello", "world"]RPUSH <key> <element> [element ...]
: 将一个或多个元素插入到列表key
的尾部(右侧)。返回插入后列表的长度。
127.0.0.1:6379> RPUSH mylist "!"
(integer) 3
# 列表现在是 ["hello", "world", "!"]LPOP <key>
: 移除并返回列表key
的头部(左侧)元素。如果列表为空或键不存在,返回nil
。
127.0.0.1:6379> LPOP mylist
"hello"RPOP <key>
: 移除并返回列表key
的尾部(右侧)元素。如果列表为空或键不存在,返回nil
。LLEN <key>
: 返回列表key
的长度。如果键不存在,返回 0。LRANGE <key> <start> <stop>
: 返回列表key
中指定区间内的元素。start
和stop
是基于 0 的下标。0
表示第一个元素,1
表示第二个,-1
表示最后一个,-2
表示倒数第二个。LRANGE mylist 0 -1
返回整个列表。
127.0.0.1:6379> RPUSH tasks "task1" "task2" "task3"
(integer) 3
127.0.0.1:6379> LRANGE tasks 0 1
1) "task1"
2) "task2"
127.0.0.1:6379> LRANGE tasks 0 -1
1) "task1"
2) "task2"
3) "task3"LINDEX <key> <index>
: 返回列表key
中下标为index
的元素。如果index
超出范围,返回nil
。LSET <key> <index> <element>
: 将列表key
下标为index
的元素的值设置为element
。如果index
超出范围,返回错误。LINSERT <key> BEFORE|AFTER <pivot> <element>
: 将元素element
插入到列表key
中,位于值pivot
的之前 (BEFORE) 或之后 (AFTER)。如果pivot
不存在,不执行操作。返回插入后列表的长度,或 -1 (pivot 未找到),或 0 (key 不存在)。LTRIM <key> <start> <stop>
: 对列表进行修剪,只保留指定区间内的元素,区间之外的元素都将被删除。常用于保持列表只存储最新的 N 个元素。
# 只保留最新的 5 个日志条目
127.0.0.1:6379> LPUSH logs "log entry N"
(integer) ...
127.0.0.1:6379> LTRIM logs 0 4
OKRPOPLPUSH <source> <destination>
: 原子地从列表source
的尾部移除一个元素,并将该元素添加到列表destination
的头部,最后返回被移除的元素。常用于实现可靠的消息队列(一个备份列表)。BRPOP <key> [key ...] <timeout>
:RPOP
的阻塞版本。如果所有给定列表都为空,连接将阻塞timeout
秒(0 表示无限期阻塞),直到有元素可用或超时。返回一个包含键名和弹出元素的二元组,超时返回nil
。BLPOP <key> [key ...] <timeout>
:LPOP
的阻塞版本。行为与BRPOP
类似,但从列表头部弹出。
五、哈希 (Hash) 类型命令
Redis 哈希是一个字符串字段 (field) 和字符串值 (value) 之间的映射。它特别适合存储对象。
HSET <key> <field> <value> [field value ...]
: 将哈希表key
中的一个或多个字段field
的值设为value
。如果字段已存在,则覆盖。如果键不存在,则创建。返回新创建的字段数量。
127.0.0.1:6379> HSET user:100 name "Alice" email "[email protected]" age 30
(integer) 3HGET <key> <field>
: 获取哈希表key
中给定字段field
的值。如果字段或键不存在,返回nil
。
127.0.0.1:6379> HGET user:100 name
"Alice"HMSET <key> <field> <value> [field value ...]
: (已废弃,推荐使用 HSET) 同时将多个field-value
对设置到哈希表key
中。总是返回OK
。HMGET <key> <field> [field ...]
: 获取哈希表key
中一个或多个给定字段的值。返回值的列表,顺序与请求字段相同,不存在的字段返回nil
。
127.0.0.1:6379> HMGET user:100 name age city
1) "Alice"
2) "30"
3) (nil)HGETALL <key>
: 获取哈希表key
中所有的字段和值。返回一个包含字段和值的列表(字段后跟其值)。如果键不存在,返回空列表。
127.0.0.1:6379> HGETALL user:100
1) "name"
2) "Alice"
3) "email"
4) "[email protected]"
5) "age"
6) "30"HDEL <key> <field> [field ...]
: 删除哈希表key
中的一个或多个指定字段。返回成功删除的字段数量。HLEN <key>
: 返回哈希表key
中字段的数量。HEXISTS <key> <field>
: 检查哈希表key
中是否存在指定的字段field
。存在返回 1,不存在返回 0。HKEYS <key>
: 获取哈希表key
中所有的字段名。HVALS <key>
: 获取哈希表key
中所有的值。HINCRBY <key> <field> <increment>
: 为哈希表key
中字段field
的值(必须是整数)加上增量increment
。返回增加后的值。如果字段不存在,先创建并设为 0 再增加。
127.0.0.1:6379> HINCRBY user:100 age 1
(integer) 31HINCRBYFLOAT <key> <field> <increment>
: 为哈希表key
中字段field
的值(可以是浮点数)加上浮点数增量increment
。返回增加后的值(字符串形式)。HSETNX <key> <field> <value>
: 只在字段field
不存在时,设置哈希表key
中该字段的值。如果字段已存在,不执行任何操作。设置成功返回 1,字段已存在返回 0。HSCAN <key> <cursor> [MATCH <pattern>] [COUNT <count>]
: 增量迭代哈希表key
中的字段和值。用法类似SCAN
。
六、集合 (Set) 类型命令
Redis 集合是字符串类型的无序集合。集合中不允许有重复的元素。添加、删除、查找的时间复杂度都是 O(1)。适合存储标签、共同好友等。
SADD <key> <member> [member ...]
: 向集合key
中添加一个或多个成员member
。忽略已存在的成员。返回成功添加的新成员数量。
127.0.0.1:6379> SADD tags:post:1 "redis" "database" "nosql"
(integer) 3
127.0.0.1:6379> SADD tags:post:1 "redis" "cache"
(integer) 1 # "redis" 已存在,只有 "cache" 被添加SMEMBERS <key>
: 返回集合key
中的所有成员。成员是无序的。
127.0.0.1:6379> SMEMBERS tags:post:1
1) "nosql"
2) "database"
3) "redis"
4) "cache"SISMEMBER <key> <member>
: 判断成员member
是否是集合key
的成员。是返回 1,不是或键不存在返回 0。SCARD <key>
: 返回集合key
的基数(成员数量)。SREM <key> <member> [member ...]
: 从集合key
中移除一个或多个成员。返回成功移除的成员数量。SPOP <key> [count]
: 随机移除并返回集合key
中的一个或多个成员。count
指定移除数量。SRANDMEMBER <key> [count]
: 随机返回集合key
中的一个或多个成员,但不移除它们。count
正数表示返回不重复成员,负数表示可能返回重复成员。- 集合运算:
SINTER <key> [key ...]
: 返回给定所有集合的交集。SINTERSTORE <destination> <key> [key ...]
: 将给定所有集合的交集存储在destination
集合中。SUNION <key> [key ...]
: 返回给定所有集合的并集。SUNIONSTORE <destination> <key> [key ...]
: 将给定所有集合的并集存储在destination
集合中。SDIFF <key> [key ...]
: 返回第一个集合与其他集合的差集(属于第一个集合但不属于其他集合的成员)。SDIFFSTORE <destination> <key> [key ...]
: 将第一个集合与其他集合的差集存储在destination
集合中。
127.0.0.1:6379> SADD set1 "a" "b" "c"
(integer) 3
127.0.0.1:6379> SADD set2 "c" "d" "e"
(integer) 3
127.0.0.1:6379> SINTER set1 set2
1) "c"
127.0.0.1:6379> SUNION set1 set2
1) "a"
2) "b"
3) "c"
4) "d"
5) "e"
127.0.0.1:6379> SDIFF set1 set2
1) "a"
2) "b"
SSCAN <key> <cursor> [MATCH <pattern>] [COUNT <count>]
: 增量迭代集合key
中的成员。用法类似SCAN
。
七、有序集合 (Sorted Set / ZSet) 类型命令
Redis 有序集合与集合类似,也是字符串成员的集合,不允许重复。但每个成员都会关联一个 double 类型的分数 (score)。Redis 正是通过分数来为集合中的成员进行排序。成员是唯一的,但分数可以重复。适合实现排行榜、范围查询等。
ZADD <key> [NX|XX] [CH] [INCR] <score> <member> [<score> <member> ...]
: 向有序集合key
添加一个或多个成员,或者更新已存在成员的分数。NX
: 只添加新成员,不更新已存在成员。XX
: 只更新已存在成员,不添加新成员。CH
: 返回值修改的成员数(包括更新分数和新添加的)。默认只返回新添加成员数。INCR
: 将成员的分数加上指定的分数(此时只能指定一个 score-member 对)。类似ZINCRBY
。
127.0.0.1:6379> ZADD leaderboard 100 "player1" 95 "player2" 110 "player3"
(integer) 3
127.0.0.1:6379> ZADD leaderboard XX CH 105 "player1" # 更新 player1 分数
(integer) 1 # CH 使得更新也计数
ZRANGE <key> <start> <stop> [WITHSCORES]
: 按分数从小到大排序,返回有序集合key
中指定区间内的成员。start
和stop
是基于 0 的排名下标。WITHSCORES
选项会同时返回成员和分数。
127.0.0.1:6379> ZRANGE leaderboard 0 -1 WITHSCORES # 获取所有成员和分数,升序
1) "player2"
2) "95"
3) "player1"
4) "105"
5) "player3"
6) "110"ZREVRANGE <key> <start> <stop> [WITHSCORES]
: 按分数从大到小排序,返回指定区间内的成员。用法同ZRANGE
。常用于获取 Top N 排行榜。
127.0.0.1:6379> ZREVRANGE leaderboard 0 0 WITHSCORES # 获取排名第一的玩家和分数
1) "player3"
2) "110"ZRANGEBYSCORE <key> <min> <max> [WITHSCORES] [LIMIT offset count]
: 按分数从小到大排序,返回有序集合key
中分数在min
和max
之间(包含边界)的成员。min
和max
可以是-inf
和+inf
表示负无穷和正无穷。- 可以使用
(
前缀表示不包含边界,如(95
表示大于 95。 LIMIT
用于分页。
127.0.0.1:6379> ZRANGEBYSCORE leaderboard 100 110 WITHSCORES
1) "player1"
2) "105"
3) "player3"
4) "110"
ZREVRANGEBYSCORE <key> <max> <min> [WITHSCORES] [LIMIT offset count]
: 同ZRANGEBYSCORE
,但按分数从大到小排序。注意max
和min
的位置。ZCARD <key>
: 返回有序集合key
的基数(成员数量)。ZCOUNT <key> <min> <max>
: 返回有序集合key
中,分数在min
和max
之间(包含边界)的成员数量。ZRANK <key> <member>
: 返回有序集合key
中成员member
的排名(按分数从小到大,排名从 0 开始)。如果成员不存在,返回nil
。ZREVRANK <key> <member>
: 返回有序集合key
中成员member
的排名(按分数从大到小,排名从 0 开始)。ZSCORE <key> <member>
: 返回有序集合key
中成员member
的分数。如果成员不存在,返回nil
。ZREM <key> <member> [member ...]
: 移除有序集合key
中的一个或多个成员。返回成功移除的成员数量。ZREMRANGEBYRANK <key> <start> <stop>
: 移除有序集合key
中指定排名区间(从小到大)的所有成员。ZREMRANGEBYSCORE <key> <min> <max>
: 移除有序集合key
中指定分数区间的所有成员。ZINCRBY <key> <increment> <member>
: 为有序集合key
中成员member
的分数加上增量increment
。返回增加后的新分数。如果成员不存在,则添加该成员,分数初始为increment
。ZSCAN <key> <cursor> [MATCH <pattern>] [COUNT <count>]
: 增量迭代有序集合key
中的成员和分数。用法类似SCAN
。- 有序集合运算 (较复杂,需要注意聚合方式):
ZUNIONSTORE <destination> <numkeys> <key> [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX]
: 计算多个有序集合的并集,并将结果存入destination
。可以指定权重WEIGHTS
和分数聚合方式AGGREGATE
(默认为 SUM)。ZINTERSTORE <destination> <numkeys> <key> [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX]
: 计算多个有序集合的交集,并将结果存入destination
。
八、发布/订阅 (Pub/Sub)
Redis 的发布/订阅功能允许客户端订阅一个或多个频道 (channel),并接收发布到这些频道的消息。
SUBSCRIBE <channel> [channel ...]
: 订阅一个或多个频道。执行此命令后,客户端会进入订阅模式,只能接收消息或执行SUBSCRIBE
,UNSUBSCRIBE
,PSUBSCRIBE
,PUNSUBSCRIBE
,PING
,QUIT
命令。
bash
# 客户端 A
127.0.0.1:6379> SUBSCRIBE news. Mytopic alerts
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "news. Mytopic"
3) (integer) 1
1) "subscribe"
2) "alerts"
3) (integer) 2PUBLISH <channel> <message>
: 向指定频道channel
发布一条消息message
。返回接收到消息的订阅者数量。
bash
# 客户端 B
127.0.0.1:6379> PUBLISH news. Mytopic "Redis 7.0 is released!"
(integer) 1 # 假设只有一个客户端 A 订阅了
客户端 A 会收到:
1) "message"
2) "news. Mytopic"
3) "Redis 7.0 is released!"UNSUBSCRIBE [channel [channel ...]]
: 退订一个或多个频道。如果不指定频道,则退订所有频道。PSUBSCRIBE <pattern> [pattern ...]
: 订阅一个或多个模式。客户端将接收到与模式匹配的所有频道的消息。例如PSUBSCRIBE news.*
会收到news. Mytopic
,news. Tech
等频道的消息。PUNSUBSCRIBE [pattern [pattern ...]]
: 退订一个或多个模式。如果不指定模式,则退订所有模式。
九、事务 (Transaction)
Redis 事务提供了一种将多个命令打包执行的机制。事务中的命令会按顺序、原子地执行,执行期间不会被其他客户端的命令打断。Redis 事务不保证回滚(如果某个命令失败,其他已执行命令不会撤销),但能保证原子性(要么全部执行,要么全部不执行——在 EXEC
前出错的情况)。
MULTI
: 标记事务块的开始。后续命令会被放入队列,而不是立即执行。返回OK
。EXEC
: 执行所有在MULTI
之后入队的命令。返回一个包含所有命令执行结果的列表。如果在MULTI
和EXEC
之间有命令入队失败(例如语法错误),EXEC
会拒绝执行事务,并返回错误。如果在EXEC
执行期间某个命令失败(例如对 String 执行 List 操作),其他命令仍会执行,EXEC
返回的结果列表中对应位置会是错误信息。DISCARD
: 取消事务,清空事务队列。返回OK
。WATCH <key> [key ...]
: 监视一个或多个键。如果在WATCH
执行之后,EXEC
执行之前,有任意被监视的键被其他客户端修改了,那么当前事务将被取消 (EXEC
返回nil
)。这提供了一种乐观锁机制。WATCH
必须在MULTI
之前执行。UNWATCH
: 取消WATCH
命令对所有键的监视。如果在执行EXEC
或DISCARD
后,监视会自动取消。
“`
127.0.0.1:6379> WATCH mycounter
OK
127.0.0.1:6379> GET mycounter
“10”
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> INCR mycounter
QUEUED
127.0.0.1:6379> SET anotherkey “value”
QUEUED
此时,如果另一个客户端执行了 SET mycounter 20
127.0.0.1:6379> EXEC
(nil) # 事务失败,因为被 WATCH 的 mycounter 被修改了
如果没有被修改
127.0.0.1:6379> EXEC
1) (integer) 11 # INCR mycounter 的结果
2) OK # SET anotherkey 的结果
“`
十、脚本 (Scripting) – Lua
Redis 支持使用 Lua 脚本来执行原子性的复杂操作。脚本在服务器端执行,减少了网络延迟,并保证了原子性。
EVAL <script> <numkeys> <key> [key ...] <arg> [arg ...]
: 执行 Lua 脚本script
。numkeys
指定后面有多少个参数是键名 (key),剩下的参数是附加参数 (arg)。脚本中可以通过KEYS[i]
访问键名,ARGV[i]
访问附加参数。
lua
-- Lua script: 原子性地获取并增加计数器,如果不存在则设为 1
local current_val = redis.call('GET', KEYS[1])
local new_val
if current_val == false then
new_val = 1
else
new_val = tonumber(current_val) + tonumber(ARGV[1])
end
redis.call('SET', KEYS[1], new_val)
return new_val
127.0.0.1:6379> EVAL "local current_val = redis.call('GET', KEYS[1]) \n local new_val \n if current_val == false then \n new_val = 1 \n else \n new_val = tonumber(current_val) + tonumber(ARGV[1]) \n end \n redis.call('SET', KEYS[1], new_val) \n return new_val" 1 mycounter 5
(integer) 6 # 假设 mycounter 不存在,设为 1,然后加 5?不,这里是直接加 5,脚本逻辑需要调整,假设是加 ARGV[1]
# 正确的脚本逻辑,假设目标是 + ARGV[1]
# EVAL "..." 1 my_incr_counter 5EVALSHA <sha1> <numkeys> <key> [key ...] <arg> [arg ...]
: 通过脚本的 SHA1 校验和来执行脚本。脚本需要先用SCRIPT LOAD
加载到服务器缓存中。这样可以避免每次都传输整个脚本。SCRIPT LOAD <script>
: 将脚本加载到服务器的脚本缓存中,返回脚本的 SHA1 校验和。SCRIPT EXISTS <sha1> [sha1 ...]
: 检查一个或多个 SHA1 校验和对应的脚本是否存在于缓存中。返回一个包含 0 或 1 的列表。SCRIPT FLUSH
: 清空服务器的 Lua 脚本缓存。SCRIPT KILL
: 尝试终止当前正在运行的、且没有执行过写操作的 Lua 脚本。
十一、持久化与其他
SAVE
: 同步执行一次数据库快照(RDB 持久化),会阻塞服务器。BGSAVE
: 异步执行一次数据库快照,由子进程完成,服务器主进程继续处理请求。LASTSAVE
: 返回最后一次成功执行快照的 Unix 时间戳。SHUTDOWN [NOSAVE|SAVE]
: 关闭 Redis 服务器。NOSAVE
表示不执行快照直接关闭(可能丢失上次快照后的数据),SAVE
表示执行快照后再关闭(如果开启了 AOF,也会处理 AOF)。默认行为取决于配置。FLUSHDB
: 删除当前数据库的所有键。危险操作!FLUSHALL
: 删除所有数据库的所有键。极度危险操作!CONFIG GET <parameter>
: 获取服务器配置参数的值。CONFIG SET <parameter> <value>
: 动态修改服务器配置参数。并非所有参数都支持动态修改。CLIENT LIST
: 列出所有连接到服务器的客户端信息。CLIENT KILL <ip:port>
或CLIENT KILL ID <client-id>
: 关闭指定的客户端连接。
结语
本指南详细介绍了 Redis 的核心命令及其用法,涵盖了从基础连接、键管理到各种数据结构的操作,以及事务、发布订阅和 Lua 脚本等高级功能。熟练掌握这些命令是高效使用 Redis 的基础。然而,Redis 的世界远不止于此,还有集群 (Cluster)、哨兵 (Sentinel)、流 (Stream) 等更高级的主题值得深入探索。
在实际应用中,除了掌握命令本身,还需要理解各种数据结构的适用场景,设计合理的键名,关注性能(例如避免慢查询如 KEYS
),并根据业务需求配置好持久化和高可用方案。希望本指南能为您在 Redis 的学习和实践道路上提供有力的支持。