Redis String 类型全解析
文章目录
- 1.引言
- 2.String 类型的核心特性:二进制安全的 “万能容器”
- 2.1 二进制安全:存什么,取什么
- 2.2 大小限制:512MB 的 “边界”
- 3.String 类型核心命令
- 3.1 基础读写:set /get
- 3.2 批量操作:mset /mget
- 3.3 专用过期与存在性命令:setnx /setex/psetex
- 3.4 计数操作:incr /incrby/decr /decrby/incrbyfloat
- 3.5 字符串处理:append /getrange/setrange /strlen
- 3.5.1 append:追加字符串
- 3.5.2 getrange:截取子串
- 3.5.3 setrange:修改子串
- 3.5.4 strlen:计算字符串长度
- 3.6 其他实用命令:flushall
- 3.7 命令小结
- 4.编码方式
- 5.应用场景
- 5.1 做缓存
- 5.2 计数功能
- 5.3 session会话
- 5.4 手机验证码
- 6.业务视角:技术如何支撑不同场景的业务需求
- 6.1 业务的核心定义
- 6.2 技术与业务的适配逻辑
- 7.小结
1.引言
在 Redis 的所有数据类型中,String(字符串)是当之无愧的 “基石”—— 它不仅是 Key 的唯一类型,也是 Value 最常用的形态。从简单的缓存存储到复杂的计数功能,从临时验证码到分布式会话,String 类型凭借 “灵活存储 + 高效操作” 的特性,支撑了分布式系统中的大量核心场景。本文将从 “基础命令→编码优化→应用场景→业务理解” 四个维度,带你吃透 Redis String 类型的所有关键知识点。
2.String 类型的核心特性:二进制安全的 “万能容器”
Redis 的 String 类型并非传统意义上的 “字符串”,而是二进制安全的字节序列容器—— 这是它区别于其他数据库字符串类型的核心优势。
2.1 二进制安全:存什么,取什么
Redis 存储 String 时,不会对数据做任何编码转换(如 MySQL 默认字符集是拉丁文,编码可能导致中文乱码),而是直接按二进制字节流存储。这意味着:
- 可存储文本数据:如 JSON、XML、普通字符串;
- 可存储二进制数据:如图片、音频、视频的字节流;
- 乱码概率极低:仅当客户端与服务器编码不一致时(如客户端用 GBK,服务器返回 UTF-8 字节流)才可能出现乱码,与 Redis本身无关。
2.2 大小限制:512MB 的 “边界”
为保证单线程模型下的 “短平快” 操作,Redis 限制单个 String 的最大大小为 512MB。这一限制既能满足绝大多数业务场景(如缓存商品详情、用户会话),又能避免超大 String 操作(如读取 1GB 二进制数据)阻塞主线程。
3.String 类型核心命令
3.1 基础读写:set /get
set
和get
是 String 最核心的命令,分别用于存储和获取键值对。
set
- 基本语法:
set key value [ex seconds] [px milliseconds] [nx|xx]
可选参数覆盖 “过期时间” 和 “存在性判断”,无需额外调用expire:
ex seconds
:设置过期时间(秒),等价于set key value + expire key seconds;px milliseconds
:设置过期时间(毫秒);nx
:仅当 Key 不存在时才设置,存在则失败(返回nil);xx
:仅当 Key 存在时才覆盖,不存在则失败(返回nil)。
get
- 基本语法:
get key
- 返回结果:
- Key 存在:返回对应的 String 值(带双引号);
- Key 不存在:返回nil;
- 若 Value 非 String 类型(如 Hash、List):直接报错(WRONGTYPE Operation against a key holding the wrong kind of value)。
3.2 批量操作:mset /mget
当需要读写多个键值对时,mset
和mget
能减少网络通信次数(避免多次set/get的网络开销),提升效率。
mset
- 基本语法:
mset key1 value1 key2 value2 ...
- 特点:原子性操作(要么全部成功,要么全部失败),不存在 “部分设置” 的情况。
mget
- 基本语法:
mget key1 key2 ...
- 特点:返回结果按传入 Key 的顺序排列,不存在的 Key 对应位置返回nil。
3.3 专用过期与存在性命令:setnx /setex/psetex
这三个命令是set可选参数的 “单独封装”,语义更明确,适合特定场景。
- setnx:set if not exists,等价于set key value nx,常用于分布式锁的 “加锁” 操作;
- setex:set with expire,等价于set key value ex seconds,直接关联过期时间;
- psetex:set with millisecond expire,等价于set key value px milliseconds,毫秒级过期。
3.4 计数操作:incr /incrby/decr /decrby/incrbyfloat
这类命令专门用于 “数值型 String” 的自增 / 自减,是实现 “计数器” 的核心工具,且天然支持线程安全(单线程串行执行)。
命令 | 功能 | 示例 | 返回值 |
---|---|---|---|
incr key | 对 Value+1(需为整数) | incr user:login:count | 自增后的值 |
incrby key n | 对 Value+n(n 为整数,可正可负) | incrby user:score 10(+10) | 自增后的值 |
decr key | 对 Value-1(需为整数) | decr goods:stock | 自减后的值 |
decrby key n | 对 Value-n(n 为整数,可正可负) | decrby goods:stock 5(-5) | 自减后的值 |
incrbyfloat | 对 Value 加减浮点数 | incrbyfloat user:balance 2.5 | 运算后的值(浮点数) |
- 特性:
- 若 Key 不存在,操作时会先将 Value 初始化为 0,再执行运算(如incr new:key返回 1);
- 若 Value 非数值型(如set str hello),执行计数命令会报错(ERR value is not an integer or out of range);
- 线程安全:单线程模型保证多个客户端同时incr同一 Key,不会出现 “计数丢失”(如两个客户端同时incr,最终结果必为 + 2)。
3.5 字符串处理:append /getrange/setrange /strlen
3.5.1 append:追加字符串
- 语法:
append key value
- 功能:将value追加到原有 String 的末尾,若 Key 不存在则直接set key value;
- 返回值:追加后 String 的总长度(单位:字节,非字符数);
redis字符串,不会对字符编码做任何处理(redis不认识字符,只认识字节)
当前的xshell终端,默认字符编码是utf8,一个汉字在utf8字符集中,通常是3个字节。
在启动redis客户端的时候,加上 --raw的选项。就能使redis客户端自动把二进制数据尝试翻译。
在xshell中,ctrl s是冻结画面 ,ctrl q解除冻结。
3.5.2 getrange:截取子串
- 语法:
getrange key start end
- 功能:截取 String 中[start, end]区间的子串(闭区间,下标从 0 开始,支持负数:-1 = 最后 1 个字节,-2 = 倒数第 2 个字节);
- 注意:若 String 含多字节字符(如汉字),按字节截取可能导致 “乱码”(如截取 “你好” 的前 2 字节,得到不完整的汉字编码);
上述问题在C++中同样存在,在Java中没事,java中字符串的基本单位是字符(占2字节的字符,按unicode方式编码的)把汉字的编码转换都处理好了。C++对汉字的处理就没那么完善
3.5.3 setrange:修改子串
- 语法:
setrange key offset value
- 功能:从offset(偏移量,0 开始)位置开始,用value覆盖原有 String 的内容;
- 返回值:修改后 String 的总长度(字节);
- 特殊情况:若 Key 不存在,会先初始化 String,offset之前的位置填充为0x00(二进制空字节);
3.5.4 strlen:计算字符串长度
- 语法:
strlen key
- 功能:返回 String 的长度(单位:字节,非字符数);
3.6 其他实用命令:flushall
- 语法:
flushall
- 功能:删除 Redis 中的所有 Key(所有数据库),生产环境慎用;
- 场景:仅用于测试环境清理数据,生产环境需通过del或scan + del批量删除指定 Key。
3.7 命令小结
命令格式 | 功能描述 | 时间复杂度 |
---|---|---|
set key value | 设置 key 的值是 value | O(1) |
get key | 获取 key 的值 | O(1) |
del key [key …] | 删除指定的 key | O(k) |
mset key value [key value …] | 批量设置指定的 key 和 value | O(k) |
mget key [key …] | 批量获取 key 的值 | O(k) |
incr key | 指定的 key 的值 +1 | O(1) |
decr key | 指定的 key 的值 -1 | O(1) |
incrby key n | 指定的 key 的值 +n | O(1) |
decrby key n | 指定的 key 的值 -n | O(1) |
incrbyfloat key n | 指定的 key 的值 +n(浮点数) | O(1) |
append key value | 指定的 key 的值追加 value | O(1) |
strlen key | 获取指定 key 的值的长度 | O(1) |
setrange key offset value | 覆盖指定 key 的从 offset 开始的部分值 | O(n) |
getrange key start end | 获取指定 key 的从 start 到 end 的部分值 | O(n) |
4.编码方式
string内部有3种编码方式
int 64位/8字节 的整数
embstr 压缩字符串,适用于短字符串
raw 普通字符串,适用于长字符串
object encoding 查看编码方式
存小数,当字符串存储。每次进行算数运算,都要把字符串转换成小数,运算后再转回字符串保存。
5.应用场景
5.1 做缓存
整体思路:
应用服务器访问数据的时候,先查询redis,如果redis上数据存在,直接从redis中取,不用再访问数据库。不存在则读取MySQL,结果返回给应用服务器并把这个数据写入到redis中。
redis再记录这些数据的同时,会给key设置一个过期时间。
redis在内存不足时也有相关的淘汰策略。
5.2 计数功能
这里写入统计数据仓库的方式是异步的,不是来一个请求,redis计数后就写入,可能是比较缓慢,但一直不停的在写入统计数据仓库,最终保证数据相同。
实际上的计数系统,还要考虑,防作弊,不同维度计数,数据持久化等问题。
5.3 session会话
在 Web 开发中,Session(会话)用于存储客户端与服务器交互的 “临时状态数据”(如用户登录信息、购物车临时数据),而 String 类型是存储 Session 的理想选择。
Cookie :浏览器存储数据的机制
Session: 服务器存储数据的机制
Session(会话)可以理解为 客户端和服务器在交互过程中产生的一些专属于该客户端的中间状态的数据。
比如一个病人去医院看病,在医院系统上记载的这个病人相关的病例 就可以理解为会话
如果每个服务器维护自己的会话数据,彼此不共享,当用户请求访问到不同的服务器上,就可能出现无法处理的情况。
把会话单独存储在redis中,此时就共享了。
5.4 手机验证码
利用expire指令,给生成的验证码设置过期时间,确保验证码的时效性。
然后在规定时间内,把短信收到的验证码提交到系统中进行比对,检验是否正确。
6.业务视角:技术如何支撑不同场景的业务需求
理解 String 类型的应用场景后,更重要的是明白 “技术与业务的关系”—— 业务是 “解决问题的过程”,技术是 “解决问题的工具”,不同业务需要不同的技术特性支撑。
6.1 业务的核心定义
“业务” 并非抽象概念,而是具体的 “问题解决流程”。例如:
- 电商平台的 “商品销售” 业务:核心是 “用户下单→库存扣减→订单生成→物流跟踪”,需要 Redis 的计数功能(扣减库存)、缓存功能(存储商品详情)支撑;
- 社交软件的 “用户登录” 业务:核心是 “用户输入账号密码→验证身份→创建会话→保持登录状态”,需要 Redis 的 Session 存储功能支撑;
- 金融 App 的 “支付验证” 业务:核心是 “用户发起支付→发送验证码→验证验证码→完成支付”,需要 Redis 的验证码存储功能支撑。
6.2 技术与业务的适配逻辑
不同业务的核心诉求不同,决定了需要选择不同的技术特性:
- 若业务诉求是 “高频读取、低延迟”(如商品详情页),选择 Redis String 的缓存功能(纯内存操作,O (1) 复杂度);
- 若业务诉求是 “实时统计、防并发冲突”(如销量计数),选择 Redis String 的incr命令(单线程安全,支持异步落库);
- 若业务诉求是 “临时数据、自动过期”(如 Session、验证码),选择 Redis String 的setex命令(自带过期时间,无需手动清理)。
简言之,Redis String 类型的灵活性,使其能适配多种业务场景 —— 但最终选择哪种用法,取决于业务的核心需求(是要 “快”,还是要 “安全”,或是要 “省内存”)。
7.小结
Redis String 类型看似简单,却承载了分布式系统中大量核心场景,其价值可归纳为三点:
- 万能存储:支持文本、二进制数据,二进制安全特性使其能存储任意格式数据;
- 高效操作:所有基础命令(set/get/incr)均为 O (1) 复杂度,配合批量命令(mset/mget)可减少网络开销;
- 灵活适配:通过setex/incr等命令,能满足缓存、计数、Session、验证码等多种场景需求。
使用 String 类型时,需注意三个关键建议:
- 合理设置 Key 命名:采用 “业务模块:功能:唯一标识”
的格式(如goods:info:1001、session:123456),便于后续维护和排查; - 控制 String 大小:避免存储超过 100KB 的大 String(如完整视频文件),防止单命令执行时间过长阻塞主线程;
- 必设过期时间:非核心永久数据(如缓存、Session、验证码)必须设置过期时间(setex或expire),避免 Redis
内存无限增长。