首页 / Redis 入门教程 / 字符串 String

Redis 入门教程

字符串 String

本教程共 40 篇 · 第 6 篇 · 更新于 2026-08-02

redisstring字符串计数器缓存分布式锁

6. 字符串 String

本节目标

  • 理解 String 是「二进制安全」的,能存文本、数字、JSON、图片字节
  • 熟练使用 SET/GET/MSET/MGET/APPEND/STRLEN
  • INCR/INCRBY/INCRBYFLOAT 做原子计数器
  • SETEX/NX/XX 选项实现过期控制与分布式锁雏形
  • 了解 GETSET、位操作,以及避免「大 key」

String 是 Redis 最基础的数据类型,也是我们用得最多的类型。它表面上像别的 KV 系统的 value,但 Redis 的 String 有几个重要特点。

6-1 什么是「二进制安全的 String」

Redis 的 String 本质是一段字节序列(byte array),可以存:

  • 普通文本(UTF-8 中文、英文)
  • 数字(整数、浮点数,Redis 会识别并支持原子增减)
  • 序列化后的对象(JSON、Protocol Buffers、Java 对象等)
  • 任意二进制数据(图片、音频片段)

「二进制安全」意味着 Redis 不会根据 \0(空字符)或编码去截断内容,存进去是什么、取出来就是什么。单个 String 的 value 上限是 512 MB

6-2 基本读写:SET / GET / MSET / MGET

127.0.0.1:6379> SET name "码上学"
OK
127.0.0.1:6379> GET name
"码上学"
127.0.0.1:6379> STRLEN name
(integer) 9

STRLEN 返回字节长度(中文 UTF-8 每个字占 3 字节,所以「码上学」是 9 字节)。

一次设置/获取多个 key,减少往返(RTT):

127.0.0.1:6379> MSET k1 v1 k2 v2 k3 v3
OK
127.0.0.1:6379> MGET k1 k2 k3
1) "v1"
2) "v2"
3) "v3"

APPEND 把内容追加到已有值的末尾(key 不存在则相当于 SET):

127.0.0.1:6379> APPEND greeting "Hello"
(integer) 5
127.0.0.1:6379> APPEND greeting " World"
(integer) 11
127.0.0.1:6379> GET greeting
"Hello World"

6-3 SET 的进阶选项(非常重要)

SET 支持一组修饰选项,让「设置值」这一个命令就能完成「条件写 + 过期」等组合动作:

SET key value [NX | XX] [GET] [EX seconds | PX ms | EXAT unix | PXAT unix | KEEPTTL]
  • EX 秒 / PX 毫秒:设置过期时间。
  • EXAT / PXAT:设置到某个 Unix 时间戳过期。
  • NX:仅当 key 不存在时才设置(「set if not exists」)。
  • XX:仅当 key 已存在时才设置。
  • GET:返回设置前的旧值(8.0 起支持)。
  • KEEPTTL:保留该 key 原有的 TTL。

示例——设置带 60 秒过期的缓存:

127.0.0.1:6379> SET session:1001 "token-abc" EX 3600
OK
127.0.0.1:6379> TTL session:1001
(integer) 3597

提示:老教程里常见 SETNXSETEXPSETEX 三个独立命令,它们现在依然可用,但官方更推荐直接用 SET + 选项一步完成,语义更清晰。比如分布式锁经典写法就是 SET lock:order 1 NX EX 30——「不存在才设、且 30 秒后自动释放」,一条命令原子搞定(详见缓存设计章节)。

6-4 原子计数器:INCR 家族

当 String 的值是「能被解析为整数」的数字时,Redis 提供原子增减命令,并发安全、无需应用层加锁:

127.0.0.1:6379> SET views 0
OK
127.0.0.1:6379> INCR views
(integer) 1
127.0.0.1:6379> INCR views
(integer) 2
127.0.0.1:6379> INCRBY views 10
(integer) 12
127.0.0.1:6379> DECR views
(integer) 11
127.0.0.1:6379> DECRBY views 5
(integer) 6

浮点数:

127.0.0.1:6379> SET price 2.71
OK
127.0.0.1:6379> INCRBYFLOAT price 0.43
"3.14"

INCR 系列命令即便 key 原本不存在,也会先初始化为 0 再自增,返回值是操作后的整数/浮点结果。

典型场景:文章阅读量、接口调用次数、库存扣减(注意超卖问题需配合其他机制)、限流器计数。

6-5 取旧值、改片段

  • GETSET key value:设置新值并返回旧值(常用于「取走当前计数并重置」)。
  • GETRANGE key start end:取子串(类似 substring,支持负索引)。
  • SETRANGE key offset value:从指定偏移量覆写。
127.0.0.1:6379> SET msg "Hello Redis"
OK
127.0.0.1:6379> GETRANGE msg 0 4
"Hello"
127.0.0.1:6379> SETRANGE msg 6 "World"
(integer) 11
127.0.0.1:6379> GET msg
"Hello World"

6-6 String 上的位操作(Bitmap 基础)

String 还能按「位」操作,实现超省内存的布尔统计(如用户每日签到):

127.0.0.1:6379> SETBIT sign:2026-08:user1 1 1
(integer) 0
127.0.0.1:6379> SETBIT sign:2026-08:user1 2 1
(integer) 0
127.0.0.1:6379> GETBIT sign:2026-08:user1 1
(integer) 1
127.0.0.1:6379> BITCOUNT sign:2026-08:user1
(integer) 2

SETBIT/GETBIT 操作单个位,BITCOUNT 统计置 1 的位数(即「签到了几天」)。关于 Bitmap / Bitfield 的细节,本教程有专门章节讲解。

6-7 String 的编码与「数字」语义

理解 String 的内部表示,能帮你写出更省内存、更高效的代码。Redis 会根据 value 的样子自动选择三种底层编码:

  • int(整数编码):当 value 是能用 64 位有符号整数表示的纯数字(如 "100""42")时,Redis 直接以整数存储,INCR 系列命令零成本自增,最省内存。
  • embstr(短字符串):较短的字符串(通常不超过 44 字节)用一块连续内存存储,分配与访问都很快。
  • raw(长字符串):更长的字符串走普通表示,适合大文本、序列化对象、二进制数据。

一个容易忽略的细节:String 里的「数字」只是看起来像数字。只有当你真正用 INCR/INCRBYFLOAT 这类命令时,Redis 才会按数值去运算;而 GET 出来的永远是字节序列,可以再参与字符串拼接。也正因如此,用 String 做计数器时务必全程走 INCR 家族,不要先 GET、在应用层加一、再 SET——那样在并发下会丢失更新,也失去了原子性。

提示:单个 String 的 value 上限是 512 MB,但别因为「能存这么大」就去塞大对象。一个几十 MB 的 String 在删除、迁移、持久化时都会拖慢实例,这就是所谓「大 key」问题。大文本或对象应拆分,或改用更合适的数据类型。

6-8 实战一:做缓存

最经典的 String 用法——把数据库查询结果缓存起来:

# 先查缓存
127.0.0.1:6379> GET user:1001:profile
(nil)
# 缓存未命中,回源数据库,再把结果写进 Redis,设 5 分钟过期
127.0.0.1:6379> SET user:1001:profile '{"id":1001,"name":"张三"}' EX 300
OK

(nil) 表示 key 不存在(与空字符串 "" 不同)。带 EX 过期可避免缓存永不失效、堆积旧数据。

6-9 实战二:分布式锁雏形

利用 SET ... NX 的原子性,多个进程抢同一把锁,只有一个能成功:

127.0.0.1:6379> SET lock:order:888 1 NX EX 30
OK          # 抢到锁
# 另一个进程再来抢
127.0.0.1:6379> SET lock:order:888 1 NX EX 30
(nil)       # 已被占用,抢不到

释放锁要用 Lua 脚本保证「只删自己的锁」(不能简单 DEL,否则可能误删别人的锁),完整做法在缓存设计章节展开。

6-10 常见误区

  • 误区:INCR 只能用于已存在的数字 key。 不存在的 key 会被当成 0 自增,不需要先 SET 0
  • 误区:String 只能存字符串。 它能存任意二进制,数字只是被识别后可做原子运算。
  • 误区:EXPIRE 后 INCR 不影响过期时间。 INCR 等写命令不会重置 TTL;但注意 RENAMESET(不带 KEEPTTL)等会清除 TTL。
  • 误区:缓存 value 越大越好。 单个 String 接近 512MB 上限会形成「大 key」,删除/迁移会卡顿,应拆分。
  • 误区:(nil)"" 一样。 GET 不存在的 key 返回 (nil)(空),GET 一个值为空串的 key 返回 "",两者含义不同。

6-11 小结

  • String 是二进制安全的字节序列,能存文本/数字/对象/二进制,上限 512 MB。
  • 读写:SET/GET/MSET/MGET/APPEND/STRLENSETEX/NX/XX/GET 选项极常用。
  • 计数:INCR/INCRBY/DECR/INCRBYFLOAT,并发安全。
  • 片段与旧值:GETRANGE/SETRANGE/GETSET
  • 位操作:SETBIT/GETBIT/BITCOUNT(Bitmap 基础)。
  • 用武之地:缓存、计数器、分布式锁雏形、限流。

提示:版本基线说明。本教程正文统一以 Redis 8.x(最新稳定版) 表述。需要留意:官方 redis.io 下载页目前把 8.8 标注为 “Latest stable”,而 GitHub 上 redis/redis 的最新发布标签为 8.10.0;二者同属 8.x 大版本,命令与数据类型差异极小,本教程以 8.10.0 为准。

掌握了 String,下一章看 Hash——当你要存「对象」并频繁改其中某字段时,它比把整个对象塞进一个 String 更合适。