[Redis] redis常见命令和String字符串解析
2026/6/5 8:50:57 网站建设 项目流程

开篇:为什么要先讲“预备知识”

很多初学者看到 Redis 命令时,会直接陷入“命令太多,要背不完”的状态。但实际上,Redis 命令背后有几条非常稳定的主线:key-value 模型、数据结构、内部编码、单线程执行、命令复杂度和使用场景。

学 Redis 不能只学命令怎么敲,还要理解命令背后的运行方式。这样后面学习 String、Hash、List、Set、Zset 时,才能知道为什么某些命令很快,为什么某些命令要谨慎使用,以及为什么 Redis 在高并发场景下表现这么好。

String 是 Redis 最基础的数据类型,但它并不只是“保存一段文本”这么简单。它还能保存数字、JSON、二进制数据,并且可以配合过期时间、条件写入、原子计数等能力,实现缓存、计数器、Session、验证码限流等常见业务。

一, 预备知识

全局命令:所有数据类型都会用到的 key 操作

Redis 有多种数据类型,但它们都围绕 key-value 展开。不同类型主要区别在 value,而 key 本身有一批通用命令。

常见全局命令包括:

命令作用复习重点
KEYS pattern查找符合模式的 key会遍历全部 key,时间复杂度O(N),生产环境慎用
EXISTS key [key ...]判断 key 是否存在返回存在的 key 数量
DEL key [key ...]删除一个或多个 key返回实际删除的 key 数量
EXPIRE key seconds设置秒级过期时间缓存场景非常常用
TTL key查看 key 剩余过期时间-1表示无过期时间,-2表示 key 不存在
TYPE key查看 key 的数据类型可返回stringlisthashsetzset

其中最需要警惕的是KEYS。它看起来很方便,可以用通配符搜索 key,例如:

KEYS user:*

但它的时间复杂度是O(N),也就是会扫描 Redis 当前库中的所有 key。如果线上 Redis 数据量很大,执行KEYS可能导致 Redis 阻塞,影响其他请求。因此它更适合开发、测试或数据量很小的场景。

EXPIRETTL则是缓存设计的基础。一个 key 被设置过期时间后,到期会被 Redis 淘汰。使用TTL查看剩余时间时要记住两个特殊值:

TTL = -1:key 存在,但没有设置过期时间 TTL = -2:key 不存在

数据结构和内部编码:Redis 对外简单,对内灵活

Redis 对外提供的数据结构是我们平时使用的类型,例如 String、Hash、List、Set、Zset。但 Redis 内部并不是只用一种固定方式保存这些结构,而是会根据数据规模和内容选择不同的内部编码。

常见关系如下:

对外数据结构常见内部编码
stringintembstrraw
hashziplisthashtable
listziplistlinkedlist、新版本常见quicklist
setintsethashtable
zsetziplistskiplist

可以使用下面的命令查看某个 key 的内部编码:

OBJECT ENCODING key

内部编码的意义在于:Redis 可以在不改变外部命令的情况下优化底层实现。比如同样是列表,小数据量时可以使用更节省内存的编码;数据量变大后,再切换到更适合大量元素操作的编码。

这对使用者来说是无感的。我们仍然使用相同的 Redis 命令,但 Redis 会尽量选择更合适的存储方式。这也是 Redis 兼顾易用性和性能的重要原因之一。

单线程模型:快,但怕慢命令

Redis 的命令执行采用单线程模型。这里的单线程主要指命令执行阶段:多个客户端可以同时连接 Redis,但 Redis 实际处理命令时,会把命令排队,然后按顺序一个个执行。

这带来一个好处:单条命令天然具有顺序执行的原子性。

比如两个客户端同时执行:

INCR counter

最终counter一定会被加两次,不会出现多个线程同时修改同一个变量时的竞争问题。因为 Redis 不会同时执行两条命令。

那为什么单线程还能这么快?主要原因有三点:

  1. Redis 数据主要存放在内存中,内存访问速度远快于磁盘。
  2. Redis 使用非阻塞 I/O 和 I/O 多路复用机制,可以高效处理大量客户端连接。
  3. 单线程避免了线程切换、锁竞争、共享数据同步等额外开销。

不过,单线程也意味着一个明显风险:如果某条命令执行很久,后面的所有命令都必须等待。

因此使用 Redis 时要特别小心这些情况:

  • 大量 key 场景下执行KEYS
  • 一次MGET/MSET传入过多 key
  • 操作大 key
  • 使用高复杂度命令处理大量数据

可以把 Redis 理解为一个非常快的单窗口服务台。它处理每个请求都很快,所以整体吞吐很高;但如果某个请求特别耗时,后面排队的人都会被卡住。

二, String 字符串

String 是 Redis 最基础的数据类型

String 是 Redis 中最基础、最常用的数据类型。需要注意的是,Redis 中所有 key 本身都是字符串,而 String 类型说的是 value 也是字符串结构。

Redis 的 String 不只可以保存普通文本,还可以保存:

  • 普通字符串,例如"hello"
  • JSON 或 XML 文本
  • 整数或浮点数
  • 二进制数据,例如图片、音频、视频片段

一个 String 最大不能超过512 MB。Redis 内部按照二进制安全的方式保存字符串,不主动处理字符集编码。也就是说,客户端传入什么字节,Redis 就保存什么字节。

基础读写命令:SET、GET、MSET、MGET

String 最基础的读写命令是SETGET

SET name "James" GET name

如果 key 已经存在,SET会直接覆盖旧值。这里有一个容易忽略的点:SET覆盖旧值时,会清除原来的 TTL。

例如某个缓存 key 原本 10 分钟后过期,如果再次执行普通SET key value,它就会变成永不过期,除非重新指定过期时间。

因此缓存场景更推荐直接写成:

SET user:1001 "{...json...}" EX 3600

SET还支持几个常用选项:

写法含义
SET key value EX seconds设置值,并设置秒级过期时间
SET key value PX milliseconds设置值,并设置毫秒级过期时间
SET key value NXkey 不存在时才设置
SET key value XXkey 存在时才设置

MGETMSET用于批量读写:

MSET k1 v1 k2 v2 k3 v3 MGET k1 k2 k3

批量命令的优势是减少网络往返。如果执行 1000 次GET,客户端和 Redis 之间要来回通信 1000 次;如果使用一次MGET获取 1000 个 key,就只需要一次网络请求。

但批量不是越大越好。因为 Redis 单线程执行命令,一次批量操作太大,也会让这条命令执行时间过长,从而阻塞后续请求。

条件写入:SETNX 和 SET NX

SETNX的含义是:只有 key 不存在时才设置成功。

SETNX lock:order:1001 1

成功返回1,失败返回0

现在更常见的写法是使用SET key value NX

SET lock:order:1001 1 NX EX 30

这种写法可以同时完成“只有不存在才写入”和“设置过期时间”,在很多限流、去重、简单锁场景中都很有用。

计数命令:String 不只是字符串,也能做数字

String 可以保存数字,因此 Redis 提供了一组计数命令:

命令作用
INCR key数值加 1
INCRBY key n数值加 n
DECR key数值减 1
DECRBY key n数值减 n
INCRBYFLOAT key n浮点数加 n,n 可以是负数

如果 key 不存在,Redis 会把它当作0处理。比如:

INCR article:1001:view

如果article:1001:view不存在,执行后结果就是1

由于 Redis 命令是单线程顺序执行的,INCR这类命令天然适合做高并发计数。它不需要像一些多线程系统那样额外使用 CAS 机制来保证计数正确。

但要注意:如果 key 对应的 value 不是合法整数或浮点数,计数命令会报错。

字符串追加和范围操作

String 还支持一些偏底层的字符串操作:

命令作用
APPEND key value在原字符串末尾追加内容
GETRANGE key start end获取指定范围的子串
SETRANGE key offset value从指定偏移位置开始覆盖字符串
STRLEN key获取字符串长度

例如:

SET greeting "Hello World" SETRANGE greeting 6 "Redis" GET greeting

最终结果是:

Hello Redis

这些命令适合处理较短字符串。如果字符串很大,范围读取或覆盖也会产生更高的处理成本。

String 的内部编码

String 的内部编码主要有三种:

编码使用场景
int可以用 8 字节长整型表示的整数
embstr小于等于 39 字节的短字符串
raw大于 39 字节的长字符串

例如:

SET key 6379 OBJECT ENCODING key

可能返回:

int

如果保存的是短字符串,例如"hello",可能使用embstr;如果字符串较长,则使用raw

这再次说明:Redis 对外提供的是统一的 String 类型,但内部会根据内容自动选择更合适的编码。

三, String 的典型业务场景

场景一:缓存

String 最经典的用法是缓存。常见架构是 Redis 作为缓存层,MySQL 等数据库作为存储层。

基本流程如下:

  1. 业务请求先查询 Redis。
  2. 如果 Redis 命中,直接返回缓存结果。
  3. 如果 Redis 未命中,再查询数据库。
  4. 将数据库结果序列化成 JSON,写入 Redis 并设置过期时间。
  5. 返回数据。

示例:

SET user:info:1001 "{...json...}" EX 3600

这种方式可以让热点数据大部分时间从 Redis 返回,减少数据库压力。

设计缓存 key 时,推荐使用有层次的命名方式:

业务名:对象名:唯一标识:属性

例如:

shop:user_info:1001 shop:user_info:1001:name

key 名要清晰,但也不要过长。过长的 key 会增加内存占用和网络传输成本。

场景二:计数器

视频播放量、文章阅读量、点赞数、接口调用次数,都可以用 String 的计数命令实现。

INCR video:5253:play_count

这种计数方式简单、高效、原子性好。真实项目中,还需要进一步考虑防刷、异步落库、按时间维度统计、数据持久化等问题。

场景三:共享 Session

在分布式 Web 服务中,如果每台服务器各自保存 Session,用户请求被负载均衡到另一台服务器时,可能会出现登录状态丢失。

把 Session 集中存储到 Redis 后,所有 Web 服务器都从 Redis 读取和更新 Session,就能解决这个问题。

常见形式:

SET session:token:abc123 "{...user info...}" EX 7200

这里的过期时间也很重要。Session 不应该永久存在,通常需要设置合理的有效期。

场景四:手机验证码和简单限流

验证码场景可以组合使用SET NXEXPIREINCRGET

一个常见思路是:

  1. SET phone:limit:手机号 1 EX 60 NX创建一分钟发送窗口。
  2. 如果 key 已存在,说明一分钟内已经请求过,再用INCR增加请求次数。
  3. 如果次数超过限制,例如超过 5 次,则拒绝发送。
  4. 生成验证码后,用SET phone:code:手机号 验证码 EX 300保存 5 分钟。
  5. 用户提交验证码时,用GET取出并比对。

示例:

SET sms:limit:13800138000 1 EX 60 NX INCR sms:limit:13800138000 SET sms:code:13800138000 637928 EX 300

这个场景很好地体现了 String 的组合能力:它本身很简单,但配合过期时间、条件写入和原子计数,就能解决不少高频业务问题。

四, 复习时最该记住的点

  1. Redis 的数据类型是 value 的类型,key 本身都是字符串。
  2. 全局命令作用于 key,EXPIRETTLTYPE是复习重点。
  3. KEYSO(N)命令,生产环境要谨慎。
  4. Redis 对外是数据结构,对内是内部编码,内部编码会自动适配数据情况。
  5. Redis 单线程执行命令,所以单条命令具有顺序执行的原子性。
  6. 单线程模型很快,但怕慢命令;大 key、大批量、高复杂度命令都可能阻塞。
  7. String 可以保存文本、数字、JSON、二进制数据,最大 512 MB。
  8. SET会覆盖旧值,并清除原 TTL,缓存场景要特别注意。
  9. MGET/MSET能减少网络开销,但批量过大也会造成阻塞。
  10. INCR/DECR系列是实现高并发计数器的核心。

总结

不是记住几个零散命令,而是要建立 Redis 的基础理解:所有操作都围绕 key-value 展开,Redis 对外提供清晰的数据结构,对内通过不同编码优化性能,并通过单线程模型实现简单而高效的命令执行。

理解 String 的基础地位。它既是最简单的数据类型,也是很多业务能力的起点。缓存、计数器、共享 Session、验证码限流这些场景,本质上都是在使用 String 的存储、过期、条件写入和原子计数能力。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询