当前位置: 首页 > news >正文

【Redis】 常用数据结构之String篇:从SET/GET到INCR的超全教程


目录

1. 前言

插播一条消息~

2. 正文

2.1 常见命令

2.1.1 SET

2.1.2 GET

2.1.3 MGET

2.1.4 MSET

多次GET与单次MGET对比分析

2.1.5 SETNX

2.2 计数命令

2.2.1 INCR

2.2.2 INCRBY

2.2.3 DECR

2.2.4 DECRBY

2.2.5 INCRBYFLOAT

2.3 其他命令

2.3.1 APPEND

2.3.2 GETRANGE

2.3.3 SETRANGE

2.3.4 STRLEN

2.4 内部编码

2.4.1编码类型及特点

2.5 典型业务场景

2.5.1 缓存功能(Redis+MySQL)

2.5.2 计数功能

2.5.3 共享会话(Session 集中管理)

2.5.4 短信验证码

3. 小结


1. 前言

日常开发中,当我们谈论Redis时,最先想到的命令是什么?是简单的SET key value,还是原子性的INCR counter?这些高频操作的背后,都指向了Redis中最基础也最核心的数据结构——String(字符串)

作为高性能的键值数据库,Redis凭借高并发支持和微秒级响应延迟的特性,成为缓存、计数器、分布式锁等场景的首选解决方案。而在Redis的五大核心数据结构中,String无疑是使用频率最高的基础类型——据统计,超过50%的Redis业务场景都依赖String实现核心功能,从简单的KV存储到复杂的分布式ID生成,其灵活性和高效性使其成为Redis初学者必须掌握的第一个数据结构。

核心价值: String作为Redis最基础的数据结构,支撑了超过50%的实际业务场景,涵盖缓存存储、分布式计数器、Session共享等核心应用。

内容预告: 本文将通过「命令实战→编码原理→业务落地」三步走的方式,帮助读者系统掌握String的使用技巧与底层逻辑。

无论是需要快速缓存用户信息,还是实现高并发场景下的精准计数,深入理解String的特性与最佳实践,都是提升Redis使用效率的关键。接下来,让我们从基础命令开始,逐步揭开String数据结构的神秘面纱。


插播一条消息~

🔍十年经验淬炼 · 系统化AI学习平台推荐

系统化学习AI平台https://www.captainbed.cn/scy/

  • 📚 完整知识体系:从数学基础 → 工业级项目(人脸识别/自动驾驶/GANs),内容由浅入深
  • 💻 实战为王:每小节配套可运行代码案例(提供完整源码)
  • 🎯 零基础友好:用生活案例讲解算法,无需担心数学/编程基础

🚀 特别适合

  • 想系统补强AI知识的开发者
  • 转型人工智能领域的从业者
  • 需要项目经验的学生

2. 正文

2.1 常见命令

2.1.1 SET

SET 命令是 Redis 中用于设置键值对的基础命令,具有高度的通用性,支持存储字符串、数字等多种类型的值,是操作 String 数据结构的核心命令之一。该命令不仅能完成基本的键值设置,还可通过可选参数实现过期时间控制、条件性设置等高级功能,广泛应用于缓存存储、分布式锁、会话管理等场景。

语法

SET key value [EX seconds] [PX milliseconds] [NX|XX] [KEEPTTL]

时间复杂度

O(1)

可选参数说明

参数含义使用场景示例
EX设置键的秒级过期时间SET cache:user "user_info" EX 3600 -- 缓存用户信息1小时
PX设置键的毫秒级过期时间SET session:123 "token" PX 1800000 -- 会话有效期30分钟
NX仅当键不存在时才设置SET lock:order "123456" NX -- 分布式锁抢占
XX仅当键存在时才更新SET config:maxCount XX 1000 -- 更新已存在配置
KEEPTTL保留键原有的过期时间SET user:name KEEPTTL "NewName" -- 更新值保留过期时间

注意事项:

在使用 SET 命令时,需特别注意覆盖已有键值对时会清除原有的过期时间。例如,若先执行 SET a 1 EX 100 为键 a 设置值 1 并指定 100 秒过期,随后直接执行 SET a 2 覆盖值为 2,此时键 a 的过期时间将被清除,变为永久有效。

关键提示: 若需在更新值的同时保留原有过期时间,可使用 KEEPTTL 参数,如 SET a 2 KEEPTTL

返回值

OK # 成功设置
nil # 条件性设置失败(如NX参数且键已存在)

示例

# 1. 基本键值设置
SET user:name "Tom"# 2. 带过期时间的设置
SET session:123 "token_abc123" EX 3600 # 有效期1小时# 3. 条件性设置(分布式锁)
SET lock:order "123456" NX EX 10 # 10秒自动释放的分布式锁

2.1.2 GET

GET 命令是 Redis 中用于读取 String 类型键值的基础命令,语法简洁直观,仅需指定目标键名即可完成操作。作为 String 类型最核心的读取命令之一,GET 在缓存查询、数据检索等场景中被广泛应用。

语法

GET key

时间复杂度

O(1)

返回值

"value" # 键存在时返回对应的字符串值
nil # 键不存在时返回

注意事项

GET 命令仅适用于 String 类型的键。当对非字符串类型(如 List、Hash、Set 等)的键执行 GET 操作时,Redis 会返回类型错误提示 WRONGTYPE Operation against a key holding the wrong kind of value

示例

# 设置值
SET user:name "Tom"# 获取值
GET user:name # 返回 "Tom"# 获取不存在的键
GET non_existent_key # 返回 nil

2.1.3 MGET

MGET 是 Redis 中用于批量获取多个字符串键值的命令,其核心优势在于批量操作特性。与单次只能获取一个键的 GET 命令相比,MGET 允许客户端通过一次请求获取多个键的值,显著减少了网络往返次数。

语法

MGET key [key ...]

时间复杂度

O(N),其中 N 表示待获取的键的数量

返回值

1) "value1"
2) "value2"
3) nil # 不存在的键对应位置返回 nil

注意事项

MGET 操作具有原子性,即整个批量获取过程会在一次请求中完成,期间不会被其他 Redis 命令打断。这保证了返回结果的一致性,避免出现部分键已读取而部分键未读取的中间状态。

示例

# 设置多个键
SET user:1:name "Alice"
SET user:2:name "Bob"# 批量获取
MGET user:1:name user:2:name user:3:name
# 返回 1) "Alice" 2) "Bob" 3) nil

2.1.4 MSET

MSET 命令用于批量设置多个键值对,通过单次请求完成多个键的设置,减少网络往返次数,提升写入效率。

语法

MSET key value [key value ...]

时间复杂度

O(N),其中 N 为键值对数量

返回值

OK # 所有键值对设置成功

注意事项

  • 原子性操作: MSET 命令会原子性地完成所有键值对的设置,要么全部成功,要么全部失败。
  • 参数数量: 输入的键值对数量必须为偶数,否则会返回语法错误。

示例

# 批量设置多个键值对
MSET user:1:name "Alice" user:1:age "25" user:1:email "alice@example.com"

多次GET与单次MGET对比分析

对比维度多次GET单次MGET
网络往返次数N次(N为键数量)1次
时间复杂度N*O(1)=O(N)O(N)
原子性非原子(可能被中断)原子(一次性完成)
代码复杂度需循环调用,代码冗长单次调用,简洁高效
性能表现高网络延迟场景下性能差减少网络IO,性能更优
适用场景键数量少(N≤5)键数量多(N>5)

结论: 在需要获取多个键值时,优先使用 MGET 命令,尤其是在分布式系统中,可显著减少网络开销,提升系统吞吐量。


2.1.5 SETNX

SETNX(SET if Not eXists)命令用于实现条件性键值设置,仅当键不存在时才设置值,返回 1 表示设置成功,0 表示键已存在。

语法

SETNX key value

时间复杂度

O(1)

返回值

(integer) 1 # 设置成功
(integer) 0 # 键已存在,设置失败

注意事项

SETNX 命令本身不支持设置过期时间,需配合 EXPIRE 命令使用,但这两个命令非原子操作,存在死锁风险。Redis 2.6.12+ 推荐使用 SET key value NX EX seconds 替代,实现原子性设置。

示例

# 原子性设置分布式锁(推荐)
SET lock:order "123456" NX EX 10 # 10秒自动释放# 传统SETNX+EXPIRE(非原子,不推荐)
SETNX lock:order "123456"
EXPIRE lock:order 10

2.2 计数命令

2.2.1 INCR

INCR 命令用于对字符串类型键值执行原子性自增操作,键不存在时会自动初始化为 0 后再自增。

语法

INCR key

时间复杂度

O(1)

返回值

(integer) 1 # 自增后的结果

注意事项

INCR 命令仅支持 64 位有符号整数范围(-9223372036854775808 至 9223372036854775807),超出范围会返回错误。

示例(文章阅读量统计)

# 初始阅读量为0
INCR article:read:1001 # 返回 (integer) 1# 再次访问,阅读量+1
INCR article:read:1001 # 返回 (integer) 2

2.2.2 INCRBY

INCRBY 命令支持自定义步长的整数自增操作,适用于批量计数场景。

语法

INCRBY key increment

时间复杂度

O(1)

返回值

(integer) 10 # 自增后的结果

示例(视频批量点赞)

# 初始点赞数为0
INCRBY video:like:2001 5 # 一次增加5个点赞,返回 (integer) 5

2.2.3 DECR

DECR 命令用于对字符串类型键值执行原子性自减操作,与 INCR 命令相对应。

语法

DECR key

时间复杂度

O(1)

返回值

(integer) 9 # 自减后的结果

示例(商品库存扣减)

# 初始库存10件
DECR product:stock:3001 # 返回 (integer) 9
DECR product:stock:3001 # 返回 (integer) 8

2.2.4 DECRBY

DECRBY 命令支持自定义步长的整数自减操作,适用于批量减少计数的场景。

语法

DECRBY key decrement

时间复杂度

O(1)

返回值

(integer) 5 # 自减后的结果

示例(订单批量取消)

# 初始待处理订单10个
DECRBY order:pending:4001 5 # 减少5个待处理订单,返回 (integer) 5

2.2.5 INCRBYFLOAT

INCRBYFLOAT 命令用于对浮点数执行原子性增减操作,支持自定义浮点型步长。

语法

INCRBYFLOAT key increment

时间复杂度

O(1)

返回值

"99.5" # 操作后的浮点数值(字符串类型)

注意事项

返回值为字符串类型,需在客户端进行类型转换。支持负步长,表示数值减少。

示例(商品价格调整)

# 初始价格99.0元
INCRBYFLOAT product:price:5001 0.5 # 返回 "99.5"# 价格下调0.3元
INCRBYFLOAT product:price:5001 -0.3 # 返回 "99.2"

2.3 其他命令

2.3.1 APPEND

APPEND 命令用于在指定键的字符串值末尾追加新内容,若键不存在则自动创建并设置初始值。

语法

APPEND key value

时间复杂度

O(N),其中 N 为追加后字符串的总长度

返回值

(integer) 11 # 追加后字符串的总长度

注意事项

  • 若键不存在,APPEND 命令等价于 SET key value
  • 对 embstr 编码的字符串执行 APPEND 会触发编码转换为 raw。

示例

# 键不存在时创建
APPEND user:log:6001 "user login" # 返回 (integer) 10# 追加内容
APPEND user:log:6001 " at 10:00" # 返回 (integer) 18GET user:log:6001 # 返回 "user login at 10:00"

2.3.2 GETRANGE

GETRANGE 命令用于获取字符串指定索引范围的子串,索引从 0 开始,支持负索引(-1 表示最后一个字符)。

语法

GETRANGE key start end

时间复杂度

O(N),其中 N 为返回子串的长度

返回值

"substring" # 指定范围内的子串

注意事项

索引越界时不会报错,会自动截取到字符串边界。例如,对长度为 5 的字符串执行 GETRANGE key 0 100,返回整个字符串。

示例

# 设置值
SET content "Redis String Tutorial"# 获取子串(前5个字符)
GETRANGE content 0 4 # 返回 "Redis"# 获取子串(最后8个字符)
GETRANGE content -8 -1 # 返回 "Tutorial"

2.3.3 SETRANGE

SETRANGE 命令用于从指定偏移量开始替换字符串的部分内容,返回替换后的字符串总长度。

语法

SETRANGE key offset value

时间复杂度

O(N),其中 N 为被替换内容的长度

返回值

(integer) 15 # 替换后字符串的总长度

注意事项

  • 偏移量从 0 开始,超出原字符串长度的部分会用空字节(\x00)填充。
  • 对 embstr 编码的字符串执行 SETRANGE 会触发编码转换为 raw。

示例

# 设置初始值
SET greeting "Hello, World!"# 从偏移量7开始替换
SETRANGE greeting 7 "Redis" # 返回 (integer) 12GET greeting # 返回 "Hello, Redis!"

2.3.4 STRLEN

STRLEN 命令用于获取字符串值的字节长度,非字符数量,需注意多字节字符(如中文)的长度计算。

语法

STRLEN key

时间复杂度

O(1)

返回值

(integer) 11 # 字符串的字节长度

注意事项

  • 对于 UTF-8 编码的中文,每个字符占 3 字节。
  • 键不存在时返回 0,与空字符串(STRLEN "" 返回 0)无法区分,需使用 EXISTS 命令判断键是否存在。

示例

# 单字节字符(ASCII)
SET en_str "Redis"
STRLEN en_str # 返回 (integer) 5# 多字节字符(UTF-8中文)
SET cn_str "Redis字符串"
STRLEN cn_str # 返回 (integer) 5 + 3*2 = 11("Redis"5字节+"字符串"6字节)

2.4 内部编码

Redis 的 String 类型通过三种内部编码实现存储优化,根据值的类型和长度自动选择最高效的存储方式:

2.4.1编码类型及特点

编码类型存储方式适用场景内存布局特点
int直接存储64位整数整数值且范围在64位有符号整数内无需额外分配SDS结构,直接存储原始整数
embstr连续内存存储RedisObject+SDS字符串长度≤44字节元数据与数据连续存储,减少内存碎片
raw分离存储RedisObject与SDS字符串长度>44字节元数据与数据分开存储,支持动态扩容

2.5 典型业务场景

2.5.1 缓存功能(Redis+MySQL)

场景描述: 通过 Redis 缓存 MySQL 中的热点数据,减少数据库访问压力,提升查询性能。

实现流程:

  1. 查询缓存:尝试从 Redis 获取数据
  2. 缓存命中:直接返回缓存数据
  3. 缓存未命中:查询 MySQL 数据库,将结果写入 Redis 并设置过期时间
  4. 缓存更新:数据变更时同步更新 Redis 缓存(可选策略:Cache Aside、Write Through)

伪代码实现:

function getUserInfo(userId):key = "user:info:{userId}"// 1. 查询缓存cachedData = GET keyif cachedData is not null:return JSON.parse(cachedData)// 2. 缓存未命中,查询数据库dbData = MySQL.query("SELECT * FROM users WHERE id = {userId}")if dbData is null:// 3. 缓存空值(防止缓存穿透)SETEX key 60 "{}" // 短期过期return nullelse:// 4. 写入缓存(设置合理过期时间)SETEX key 1800 JSON.stringify(dbData) // 30分钟过期return dbData

键名设计规范:

  • 格式:业务:模块:唯一标识,如 user:info:1001
  • 长度限制:≤40字节,避免内存浪费

命名示例:

  • 用户信息: user:info:{userId}
  • 商品库存: product:stock:{productId}
  • 文章详情: article:detail:{articleId}

缓存更新策略:

  • Cache Aside: 读操作命中缓存返回,未命中查库并更新缓存;写操作先更新数据库,再删除缓存(避免脏数据)
  • Write Through: 写操作同时更新数据库和缓存,保证数据一致性(性能略低)

2.5.2 计数功能

场景描述: 实现高并发场景下的精准计数,如文章阅读量、视频播放次数、商品点赞数等。

核心挑战与解决方案:

  1. 防作弊措施:

    • IP 限流: INCR limit:ip:{ip} + EXPIRE 60 — 限制单 IP 访问频率
    • 用户登录验证:仅登录用户的操作计入有效计数
    • 行为验证码:关键场景强制验证(如秒杀活动)
  2. 多维度计数:

    • 按时间维度:日/周/月统计(article:read:daily:1001:20231001)
    • 按用户维度:不同用户群体统计(product:like:user:{userId}:{productId})

实现示例:

# 日阅读量
INCR article:read:daily:1001:20231001# 周阅读量
INCR article:read:weekly:1001:202340
  1. 避免单点问题:

    • 使用 Redis 集群(主从+哨兵)保证高可用
    • 键名添加哈希标签(如 {article}:read:1001)确保相关键落在同一节点
  2. 数据持久化到底层数据源:

    • 定时任务:通过 CRON 任务定期将 Redis 计数同步到 MySQL
    # 获取当日所有文章阅读量
    SCAN 0 MATCH article:read:daily:*:20231001 COUNT 100# 批量同步到 MySQL(伪代码)
    for each key in scanResult:articleId = extractArticleId(key)count = GET keyMySQL.execute("UPDATE article_stats SET daily_read = {count} WHERE id = {articleId}")
    


2.5.3 共享会话(Session 集中管理)

场景描述: 在分布式系统中,将原本存储在应用服务器本地的 Session 统一存储到 Redis,实现多实例间的 Session 共享。

架构演进:

  • 传统方案: Session 存储在 Tomcat/Jetty 本地,多实例间通过 Session Replication 同步(效率低)
  • 优化方案: Session 存储在 Redis,所有应用实例通过 Redis 读写 Session 数据

实现步骤:

  1. Session 创建:用户登录时生成唯一 SessionID,将用户信息存储到 Redis
  2. Session 传递:通过 Cookie 或 URL 参数传递 SessionID
  3. Session 读取:应用实例通过 SessionID 从 Redis 获取用户信息
  4. Session 过期:设置 Redis 键过期时间(如 30 分钟),自动清理无效 Session

Redis 命令实现:

# 1. 存储用户Session(30分钟过期)
SESSION_ID = "uuid-123456"
HMSET session:{SESSION_ID} user_id 1001 username "Alice" status "online"
EXPIRE session:{SESSION_ID} 1800# 2. 获取Session信息
HGETALL session:{SESSION_ID}# 3. 延长Session有效期(用户活跃时)
EXPIRE session:{SESSION_ID} 1800

优势:

  • 高可用: Redis 集群保证 Session 数据不丢失
  • 扩展性: 支持应用服务器水平扩展,无需担心 Session 同步问题
  • 灵活性: 可自定义 Session 过期时间,支持分布式锁实现并发控制

2.5.4 短信验证码

场景描述: 用户注册或登录时,通过短信发送验证码,Redis 用于存储验证码并控制发送频率。

实现流程:

  1. 生成验证码:生成 6 位随机数字
  2. 频率控制:限制同一手机号的发送频率(如 1 分钟内 1 条)
  3. 存储验证码:将验证码存储到 Redis 并设置过期时间(如 15 分钟)
  4. 验证验证码:用户提交验证码后与 Redis 中存储的值比对

Redis 命令实现:

PHONE = "13800138000"
CODE = "654321"# 1. 频率控制(1分钟内只能发送1条)
SETNX verify:limit:{PHONE} 1 EX 60
if result == 0:raise Error("1分钟内只能发送1条验证码")# 2. 存储验证码(15分钟过期)
SETEX verify:code:{PHONE} 900 {CODE}# 3. 验证验证码
STORED_CODE = GET verify:code:{PHONE}
if USER_INPUT_CODE == STORED_CODE:# 验证成功,删除验证码(防止重复使用)DEL verify:code:{PHONE}return "验证通过"
else:return "验证码错误或已过期"

安全措施:

  • 频率限制: 通过 SETNX 实现发送频率控制,防止短信轰炸
  • 短期有效: 验证码 15 分钟过期,降低被盗用风险
  • 验证后删除: 防止验证码被重复使用
  • IP 限制: 可选增加 IP 维度的发送限制,增强安全性

3. 小结

String 类型作为 Redis 最基础也最常用的数据结构,凭借其高效的存储和原子性操作,支撑了超过 50% 的实际业务场景。本文从命令详解、内部编码到业务实践,全面介绍了 String 类型的核心特性:

  1. 命令体系: 掌握了 SET/GET 基础操作、MGET/MSET 批量操作、INCR/DECR 原子计数等 17 个核心命令的使用方法,理解了每个命令的语法、返回值和注意事项。

  2. 内部优化: 深入了解了 int/embstr/raw 三种内部编码的存储策略及转换规则,能够根据数据特征优化存储效率。

  3. 业务落地: 通过缓存功能、计数系统、共享会话、短信验证码四个典型场景,掌握了 String 类型在实际开发中的最佳实践,包括键名设计、性能优化和数据安全。

合理利用 String 类型的特性,能够显著提升系统性能与稳定性。后续将继续探讨 Redis 的其他数据结构(Hash、List、Set 等),敬请关注。

http://www.dtcms.com/a/362982.html

相关文章:

  • Jetson Thor平台JP7.0版本96712 GMSL相机驱动调试记录
  • 科技信息差(9.2)
  • 企业级按钮弹层组件封装思路
  • 第四章 windows实战-emlog
  • 关于嵌入式学习——嵌入式硬件1
  • 【JavaScript】读取商品页面中的结构化数据(JSON-LD),在不改动服务端情况下,实现一对一跳转
  • 不只是一台玩具车:开源燃料电池机器人HydroBot全揭秘
  • 基金交易量预测比赛_数据分析
  • AI-调查研究-67-具身智能 核心技术构成全解析:感知、决策、学习与交互的闭环系统
  • Caffeine介绍
  • windows docker(二) 启动存在的容器
  • 【芯片良率:半导体制造的生死线,如何避免陷阱并提升竞争力?】
  • OpenCV计算机视觉实战(23)——目标检测详解
  • 在Docker中安装MySQL时3306端口占用问题
  • 广度优先搜索(BFS, Breadth-First Search)
  • 书写腾讯天气遇到的问题
  • LeetCode 777.在LR字符串中交换相邻字符
  • PyTorch 面试题及详细答案120题(106-115)-- 理论与拓展
  • LeetCode 刷题【61. 旋转链表】
  • SAP-MM 配置工厂的名称时候,容易疏忽的点
  • Linux操作系统(6)
  • 《驾驭云原生复杂性:隐性Bug的全链路防御体系构建》
  • 线程安全问题及解决方案
  • STM32 - Embedded IDE - GCC - 如何在工程中生成.bin格式固件
  • 从API到AI Agent:落地模型上下文协议(MCP)的设计模式与核心步骤
  • 【提示词】...(后续单元)在Prompt 的作用
  • [Dify 专栏] 如何通过 Prompt 在 Dify 中模拟 Persona:即便没有专属配置,也能让 AI 扮演角色
  • 【51单片机】【protues仿真】基于51单片机呼叫系统
  • 【Qt】QToolBar、QToolButton的常用用法
  • VR智慧楼宇技术:打造智能办公空间的卓越方案​