第三篇:一条 Redis SET 命令到底经历了什么?

📅 2026/7/27 1:44:04 👁️ 阅读次数 📝 编程学习
第三篇:一条 Redis SET 命令到底经历了什么?

引言

前两篇已经建立了 Redis 的基本运行模型。

我们知道:

Spring Boot 是一个独立进程 Redis Server 也是一个独立进程

两者拥有各自独立的内存空间。

Java 后端不能直接修改 Redis 进程中的内存,只能通过 Redis 客户端发送命令,由 Redis Server 真正执行操作。

例如在 Spring Boot 中写下:

stringRedisTemplate.opsForValue() .set("user:name", "张三");

表面上看,这只是一行普通的 Java 代码。

但它背后实际上经过了多层调用:

业务代码 → StringRedisTemplate → Spring Data Redis → Redis 客户端 → TCP Socket → Redis Server → 修改 Redis 内存 → 返回执行结果

这一篇就沿着这条链路,完整分析:

一条SET命令,从 Java 代码出发,到 Redis 真正保存数据,中间到底经历了什么?


一、先看这行代码做了什么

假设 Spring Boot 项目中已经注入了StringRedisTemplate

@Service public class UserService { private final StringRedisTemplate stringRedisTemplate; public UserService( StringRedisTemplate stringRedisTemplate ) { this.stringRedisTemplate = stringRedisTemplate; } public void saveUserName() { stringRedisTemplate.opsForValue() .set("user:name", "张三"); } }

我们真正关心的是这一行:

stringRedisTemplate.opsForValue() .set("user:name", "张三");

它对应的 Redis 原生命令是:

SET user:name 张三

最终 Redis 中会形成一条数据:

user:name → 张三

但 Java 代码并不是直接执行 Redis 命令。

中间还经过了多层封装。


二、先分清这条链路中的几个角色

在分析调用过程之前,先把相关角色分清楚。

1. 业务代码

也就是我们自己编写的代码:

stringRedisTemplate.opsForValue() .set("user:name", "张三");

业务代码表达的是:

我要在 Redis 中保存一个 Key-Value。

业务层不需要自己处理 Socket、网络协议和字节传输。


2. StringRedisTemplate

StringRedisTemplate是 Spring Data Redis 提供的操作工具。

它主要用于操作字符串形式的 Key 和 Value。

例如:

stringRedisTemplate.opsForValue() .set("user:name", "张三");

读取:

String name = stringRedisTemplate .opsForValue() .get("user:name");

删除:

stringRedisTemplate.delete("user:name");

它帮助我们把 Redis 原生命令包装成更符合 Java 使用习惯的 API。

但是:

StringRedisTemplate不是 Redis Server,也不负责真正保存数据。

它只是当前 Spring Boot 进程中的一个 Java 对象。


3. Spring Data Redis

Spring Data Redis 是 Spring 提供的 Redis 访问抽象层。

它负责处理:

操作接口封装 序列化配置 连接获取 异常转换 命令调用 结果转换

例如:

opsForValue().set(key, value)

最终会被转换为底层 Redis 客户端能够执行的命令操作。

它类似于数据库访问中的:

MyBatis / JPA

但它们操作的目标不同:

MyBatis / JPA → 访问关系型数据库 Spring Data Redis → 访问 Redis

4. Redis 客户端

真正负责与 Redis Server 建立网络连接的,是底层 Redis 客户端。

Java 中常见的 Redis 客户端包括:

Lettuce Jedis Redisson

Spring Boot 项目中,我们可能只直接使用StringRedisTemplate,但在更底层,仍然需要具体客户端负责:

建立连接 发送命令 接收响应 处理网络异常 管理连接状态

整体关系可以理解为:

StringRedisTemplate → Spring Data Redis → Lettuce 或其他客户端 → Redis Server

5. Redis Server

Redis Server 才是真正执行命令的服务端。

它负责:

接收客户端命令 解析命令 查找 Key 修改数据结构 管理过期时间 返回执行结果

真正的数据最终保存在 Redis 进程管理的内存中。


三、整个调用链先看一遍

当我们执行:

stringRedisTemplate.opsForValue() .set("user:name", "张三");

整体过程可以概括为:

第一步:业务代码调用 StringRedisTemplate 第二步:StringRedisTemplate 选择 Value 操作接口 第三步:Key 和 Value 被序列化成字节数据 第四步:Spring Data Redis 获取 Redis 连接 第五步:底层客户端生成 SET 命令 第六步:命令通过 TCP Socket 发送给 Redis 第七步:Redis Server 读取并解析命令 第八步:Redis 在自己的内存中保存数据 第九步:Redis 返回执行结果 第十步:Java 客户端接收并转换结果

下面逐步展开。


四、第一步:调用 opsForValue()

代码:

stringRedisTemplate.opsForValue()

这里的Value并不是 Java 中任意类型的 Value,而是对应 Redis 的 String 数据类型操作。

Redis 虽然经常被描述为 Key-Value 数据库,但 Value 并不只有普通字符串。

Redis 还支持:

String Hash List Set ZSet

Spring Data Redis 为不同数据类型提供了不同的操作入口。

例如:

stringRedisTemplate.opsForValue();

用于 String。

stringRedisTemplate.opsForHash();

用于 Hash。

stringRedisTemplate.opsForList();

用于 List。

stringRedisTemplate.opsForSet();

用于 Set。

stringRedisTemplate.opsForZSet();

用于 ZSet。

所以:

opsForValue()

可以理解为:

我要获取 Redis String 类型的操作接口。

它并不是立即向 Redis 发送命令。

真正的操作发生在后面的:

.set("user:name", "张三");

五、第二步:StringRedisTemplate 处理 Key 和 Value

我们传入的是两个 Java 字符串:

"user:name"

和:

"张三"

但网络传输不能直接发送 JavaString对象。

Java 对象只存在于当前 JVM 进程的内存中。

Redis Server 不认识 Java 对象,也不知道什么是:

java.lang.String

因此,在发送命令之前,需要把 Java 字符串转换成字节数据。

整体过程是:

Java String → 序列化 → byte[] → 网络传输

StringRedisTemplate通常会按照字符串方式处理 Key 和 Value。

例如:

"user:name" → 字符串编码 → 字节数组
"张三" → 字符串编码 → 字节数组

这些字节才能通过网络发送给 Redis。


六、什么是序列化

序列化可以先理解为:

将当前程序中的对象,转换成适合存储或传输的数据格式。

例如 Java 中有一个对象:

User user = new User( 1001L, "张三" );

这个User对象存在于 JVM 堆内存中。

Redis Server 无法直接接收这个 Java 对象。

需要先转换成某种形式,例如 JSON:

{ "id": 1001, "name": "张三" }

再把 JSON 转换成字节,通过网络发送。

完整过程是:

Java User 对象 → JSON 字符串 → 字节数组 → 网络传输 → Redis 保存

读取时则反过来:

Redis 字节数据 → JSON 字符串 → Java User 对象

这就是:

序列化 反序列化

对于当前示例:

stringRedisTemplate.opsForValue() .set("user:name", "张三");

Key 和 Value 本身就是字符串,所以序列化过程比较简单。

但当后面使用RedisTemplate保存对象时,序列化会成为一个非常重要的问题。


七、第三步:获取 Redis 连接

要向 Redis 发送命令,Spring Boot 必须先与 Redis Server 建立连接。

连接信息通常写在配置文件中:

spring: data: redis: host: 127.0.0.1 port: 6379

如果 Redis 配置了用户名和密码,还可能包括:

spring: data: redis: host: 127.0.0.1 port: 6379 username: app_user password: redis_password

这些配置告诉客户端:

Redis 在哪台服务器 监听哪个端口 使用什么身份连接

整体目标地址可以理解为:

127.0.0.1:6379

其中:

127.0.0.1 → Redis 所在主机 6379 → Redis 监听端口

八、每次 SET 都会重新建立 TCP 连接吗

一般不会把正常使用方式理解成:

执行一次 SET → 建立一次连接 → 发送命令 → 关闭连接

如果每执行一条命令都重新完成 TCP 连接建立和关闭,额外开销会比较大。

正常情况下,Spring 容器会管理 Redis 连接相关组件,客户端也会复用已经建立的连接,或者通过连接管理机制获取可用连接。

可以先简单理解为:

Spring Boot 启动 → 创建 Redis 客户端相关组件 → 建立或准备 Redis 连接 执行 Redis 命令 → 获取可用连接 → 发送命令 → 接收结果 → 连接继续复用

具体的连接管理方式与使用的客户端和配置有关。

现阶段需要掌握的是:

StringRedisTemplate不负责保存数据,但它会通过底层连接把命令发送给 Redis Server。


九、第四步:底层客户端生成 Redis 命令

业务代码是:

stringRedisTemplate.opsForValue() .set("user:name", "张三");

底层要表达成 Redis 能理解的命令:

SET user:name 张三

但通过 TCP 发送时,并不是简单地把控制台中看到的文本原样复制过去。

客户端需要按照 Redis 通信协议组织命令数据。

可以先把它抽象理解为:

命令名称:SET 参数1:user:name 参数2:张三

底层客户端会将它编码为 Redis Server 能够解析的字节格式。

整体过程是:

Java API 调用 → Redis 命令对象 → 协议编码 → 字节数据

最终这些字节才会进入 TCP 连接。


十、Redis 协议解决了什么问题

Java、Python、Node.js、Go 等语言都可以操作 Redis。

例如:

Java 客户端 Python 客户端 Node.js 客户端 Go 客户端

这些语言的对象模型完全不同。

Redis Server 不可能分别理解:

Java String Python str JavaScript string Go string

所以客户端和 Redis Server 之间必须约定一种统一通信格式。

这个统一格式解决了:

命令如何表示 参数如何分隔 字符串长度如何表达 数组如何表达 返回值如何表示 错误信息如何表示

只要客户端按照协议发送数据,Redis Server 就能够解析。

因此:

Java 客户端 → 把 Java 调用转换成 Redis 协议 Redis Server → 按照 Redis 协议解析命令

客户端语言可以不同,但发送给 Redis Server 的命令语义是一致的。


十一、可以把 Redis 客户端和 Retrofit 再做一次类比

Android 调用后端接口时,我们可能写:

apiService.getUserInfo(1001)

表面上是 Kotlin 方法调用。

底层过程可能是:

Kotlin 方法调用 → Retrofit 解析注解 → OkHttp 构造 HTTP 请求 → 通过 TCP/TLS 发送 → Spring Boot 接收请求

Redis 操作也是类似的:

Java 方法调用 → StringRedisTemplate → Redis 客户端构造命令 → 通过 TCP 发送 → Redis Server 接收命令

对应关系可以理解为:

Android 请求后端Spring Boot 请求 Redis
API 方法RedisTemplate 方法
RetrofitSpring Data Redis
OkHttpLettuce、Jedis 等客户端
HTTP 请求格式Redis 协议格式
Spring Boot ServerRedis Server
Controller 执行业务Redis 执行命令

两者的共同点是:

本地的方法调用只是入口,真正的操作发生在另一个进程或另一台服务器中。


十二、第五步:通过 TCP Socket 发送命令

客户端把命令编码成字节后,会通过 TCP Socket 发送给 Redis。

链路可能是:

Spring Boot 服务器 127.0.0.1:随机端口 ↓ TCP Redis Server 127.0.0.1:6379

如果 Redis 在另一台服务器上,则可能是:

应用服务器 10.0.0.10 ↓ 内网 TCP Redis 服务器 10.0.0.20:6379

TCP 负责把字节从客户端可靠地传输到 Redis Server。

这里需要分清:

Redis 协议 → 规定发送的数据表示什么意思 TCP → 负责把这些字节传送到对方

它们不是同一个概念。

可以类比 HTTP:

HTTP → 规定请求行、请求头、请求体的含义 TCP → 负责传输 HTTP 数据

Redis 也是:

Redis 协议 → 规定命令和返回值如何表达 TCP → 负责传输协议数据

十三、第六步:Redis Server 接收命令

Redis Server 启动后,会监听指定端口。

常见默认端口是:

6379

当客户端连接到 Redis 后,Redis 会接收客户端发来的字节数据。

可以把这个过程简单理解为:

Redis 监听端口 ↓ 收到客户端数据 ↓ 按照 Redis 协议解析 ↓ 识别出 SET 命令

Redis 解析后会得到:

命令:SET Key:user:name Value:张三

此时 Redis 才真正知道客户端希望执行什么操作。


十四、第七步:Redis 查找对应的命令处理逻辑

Redis 支持大量命令,例如:

SET GET DEL EXPIRE INCR HSET LPUSH SADD ZADD

收到命令后,Redis 需要找到对应的处理逻辑。

例如:

SET user:name 张三

Redis 会识别出:

这是一个 SET 命令

然后执行 SET 对应的数据写入流程。

如果命令不存在,例如:

SE user:name 张三

Redis 无法识别,就会返回错误。

如果参数数量不对,例如:

SET user:name

Redis 也会返回参数错误。

因此 Redis Server 并不是接收到任意文本后直接保存,而是会先完成:

命令识别 参数检查 权限判断 数据操作 结果返回

十五、第八步:Redis 修改自己的内存数据

命令解析成功后,Redis 才开始真正修改数据。

原本 Redis 中可能没有:

user:name

执行:

SET user:name 张三

之后,Redis 自己管理的内存中会出现:

user:name → 张三

注意,这份数据不在 Spring Boot 的 JVM 中。

整体内存关系是:

Spring Boot 进程 ├── StringRedisTemplate 对象 ├── Redis 客户端对象 └── 业务对象 Redis 进程 └── user:name → 张三

Spring Boot 只是发出了请求。

真正的数据属于 Redis 进程。


十六、如果 Key 已经存在会发生什么

假设 Redis 中已经有:

user:name → 李四

再次执行:

SET user:name 张三

默认情况下,原来的值会被覆盖:

执行前: user:name → 李四 执行后: user:name → 张三

这和给变量重新赋值很像:

String userName = "李四"; userName = "张三";

但二者的运行位置不同。

Java 变量赋值:

修改当前 JVM 内存

RedisSET

通过网络通知 Redis 修改 Redis 进程内存

十七、SET 还可以带哪些条件

最简单的 SET 是:

SET user:name 张三

还可以设置过期时间:

SET verify:code:13800000000 9527 EX 300

表示:

保存验证码 9527 300 秒后过期

还可以要求 Key 不存在时才能写入:

SET submit:user:1001 1 NX

这里的NX可以理解为:

Not Exists 只有 Key 不存在时才设置成功

也可以要求 Key 已存在时才更新:

SET user:name 张三 XX

这里的XX表示:

只有 Key 已存在时才更新

因此,SET 并不只是最简单的赋值,还可以附带条件和生命周期。

这些能力都由 Redis Server 在执行命令时处理。


十八、第九步:Redis 返回执行结果

Redis 成功执行:

SET user:name 张三

通常会返回成功结果。

redis-cli中可能看到:

OK

底层返回的不是 JavaString对象,而是按照 Redis 协议编码的响应数据。

客户端收到响应后,会完成:

网络字节 → 协议解码 → Java 可识别的结果

然后 Spring Data Redis 再把结果交还给上层调用代码。

因此返回链路是:

Redis 执行完成 ↓ 生成响应 ↓ 通过 TCP 返回 ↓ Redis 客户端接收 ↓ 协议解码 ↓ Spring Data Redis 转换结果 ↓ 业务代码继续执行

十九、为什么 set() 方法通常没有返回值

我们使用:

stringRedisTemplate.opsForValue() .set("user:name", "张三");

时,set()方法通常被当成一个写入操作使用,业务层并不一定需要直接处理 Redis 返回的OK

Spring Data Redis 已经对底层返回进行了封装。

如果执行失败,例如:

Redis 无法连接 连接超时 认证失败 命令执行异常

客户端通常会将异常传递到 Java 程序。

因此业务层看到的可能不是:

返回 false

而是抛出 Redis 访问相关异常。

这意味着:

调用set()并不等于数据一定已经成功写入,网络和服务异常仍然需要考虑。


二十、如果 Redis 没启动会发生什么

假设配置为:

spring: data: redis: host: 127.0.0.1 port: 6379

但本机没有启动 Redis。

此时执行:

stringRedisTemplate.opsForValue() .set("user:name", "张三");

底层客户端尝试连接:

127.0.0.1:6379

但没有 Redis Server 监听该端口。

整体过程变成:

Java 发起 Redis 操作 ↓ 客户端尝试获取连接 ↓ 连接 Redis 失败 ↓ 抛出连接异常

这再次说明:

引入 Redis 依赖 ≠ 已经拥有 Redis Server

Maven 或 Gradle 引入的是:

Java 客户端和 Spring 封装

真正的 Redis 服务仍然需要单独安装并启动。


二十一、如果 Redis 在远程服务器上会怎样

假设 Spring Boot 配置:

spring: data: redis: host: 10.0.0.20 port: 6379

整体调用链不变:

StringRedisTemplate → Redis 客户端 → TCP → Redis Server

只不过数据需要经过网络,从应用服务器发送到 Redis 服务器。

这时可能增加一些新的问题:

网络延迟 网络中断 防火墙拦截 密码错误 连接数量限制 Redis 服务不可用

所以 Redis 虽然速度很快,但它仍然是一次远程服务调用。

不能把它完全等同于读取 Java 本地变量。


二十二、Redis 为什么快,但仍然比本地变量多一步

读取 Java 本地变量:

String name = userName;

链路是:

当前代码 → 当前 JVM 内存

读取 Redis:

String name = stringRedisTemplate .opsForValue() .get("user:name");

链路是:

当前代码 → 序列化 → 客户端 → TCP → Redis → 查询内存 → TCP 返回 → 反序列化

显然,Redis 比读取本地变量多了很多步骤。

所以从调用距离来看:

JVM 本地变量 通常比访问 Redis 更快

但 Redis 的价值不只是单次访问速度。

它还解决了:

多个实例共享 自动过期 原子操作 数据结构 集中管理 跨服务器访问

因此可以这样理解:

本地变量 → 距离最近,但只能当前进程使用 Redis → 多了一次网络调用,但多个进程可以共享

二十三、为什么多个后端实例可以看到同一个值

假设系统部署了三个 Spring Boot 实例:

Spring Boot A Spring Boot B Spring Boot C

它们都连接:

10.0.0.20:6379

A 执行:

stringRedisTemplate.opsForValue() .set("user:name", "张三");

实际修改的是:

Redis Server 内存 user:name → 张三

B 执行:

String name = stringRedisTemplate .opsForValue() .get("user:name");

B 访问的也是同一个 Redis Server。

所以可以读取到:

张三

整体结构是:

Spring Boot A ─┐ Spring Boot B ─┼── Redis Server Spring Boot C ─┘

并不是 A 把自己的 Java 变量同步给了 B。

而是 A 和 B 都在访问第三方 Redis 服务。


二十四、保存 Java 对象时又多了什么步骤

保存字符串:

stringRedisTemplate.opsForValue() .set("user:name", "张三");

相对简单,因为 Key 和 Value 都是字符串。

但如果保存用户对象:

User user = new User( 1001L, "张三" );

不能直接把对象发给 Redis。

常见做法之一是先转换成 JSON:

String userJson = objectMapper .writeValueAsString(user);

然后写入:

stringRedisTemplate.opsForValue() .set( "user:info:1001", userJson );

完整过程是:

Java User 对象 ↓ JSON 序列化 ↓ 字符串字节 ↓ Redis 客户端 ↓ TCP Redis Server ↓ 保存 JSON 数据

读取时:

String userJson = stringRedisTemplate .opsForValue() .get("user:info:1001"); User user = objectMapper.readValue( userJson, User.class );

过程是:

Redis 返回 JSON ↓ Java 获取字符串 ↓ JSON 反序列化 ↓ 恢复成 User 对象

所以 Redis 保存 Java 对象时,必须考虑序列化格式。


二十五、为什么序列化格式必须统一

假设写入时使用 JSON:

{ "id": 1001, "name": "张三" }

读取时也应该按照 JSON 解析。

如果写入端使用一种格式,读取端却按照另一种格式解析,就可能失败。

例如:

写入端 → JDK 二进制序列化 读取端 → 按照 JSON 解析

两边格式不一致,无法正确还原对象。

这也是为什么多个服务共用 Redis 时,需要提前约定:

Key 命名规则 Value 数据格式 字符编码 对象字段结构 过期时间

否则即使它们连接的是同一个 Redis,也可能无法正确理解彼此写入的数据。


二十六、一次 GET 命令的链路

理解完 SET,再看 GET 就很容易了。

Java 代码:

String name = stringRedisTemplate .opsForValue() .get("user:name");

完整链路:

1. Java 调用 get() 2. StringRedisTemplate 序列化 Key 3. Spring Data Redis 获取连接 4. 客户端生成 GET 命令 5. 通过 TCP 发送 GET user:name 6. Redis Server 解析 GET 命令 7. Redis 在自己的内存中查找 Key 8. 找到 Value:张三 9. Redis 编码返回结果 10. 客户端接收并解码 11. StringRedisTemplate 转换为 Java String 12. 业务代码得到“张三”

如果 Key 不存在:

Redis 找不到 user:name → 返回空结果 → Java 最终得到 null

所以代码通常需要处理:

String name = stringRedisTemplate .opsForValue() .get("user:name"); if (name == null) { // Key 不存在,或者已经过期 }

二十七、一次 DEL 命令的链路

Java 代码:

Boolean deleted = stringRedisTemplate.delete("user:name");

底层对应:

DEL user:name

整体过程:

Java 调用 delete() ↓ Key 被序列化 ↓ 客户端生成 DEL 命令 ↓ TCP 发送 ↓ Redis 找到 Key ↓ 从 Redis 数据中删除 ↓ 返回删除数量

如果 Key 存在并被成功删除:

删除数量:1

如果 Key 原本不存在:

删除数量:0

Spring Data Redis 会把底层结果转换成适合 Java 使用的返回值。


二十八、一条命令的完整时序图

以:

stringRedisTemplate.opsForValue() .set("user:name", "张三");

为例,完整时序可以整理为:

业务代码 | | set("user:name", "张三") ↓ StringRedisTemplate | | 序列化 Key 和 Value ↓ Spring Data Redis | | 获取 Redis 连接 ↓ Lettuce / Jedis 等客户端 | | 编码 SET 命令 | 通过 TCP 发送 ↓ Redis Server | | 解析命令 | 校验参数 | 修改 Redis 内存 | 生成响应 ↓ Redis 客户端 | | 接收响应 | 协议解码 ↓ Spring Data Redis | | 转换结果 ↓ 业务代码继续执行

这就是一条 Redis 命令的完整生命周期。


二十九、这条链路中哪里可能失败

一条 SET 命令并不一定永远成功。

可能出现问题的位置包括:

1. 配置错误

Redis 地址错误 端口错误 密码错误 数据库编号错误

2. Redis 没有启动

客户端连接 6379 → 没有服务监听 → 连接失败

3. 网络问题

网络中断 防火墙拦截 连接超时 服务器不可达

4. 序列化失败

例如对象中存在无法正常序列化的字段。

Java 对象 → JSON 转换失败 → 命令尚未发送

5. Redis 内存问题

Redis 可能达到内存限制,或者根据配置拒绝某些写入。

6. 命令类型错误

例如一个 Key 原本保存的是 Hash,却使用了不匹配的数据结构命令。

因此真实项目中,还需要考虑:

异常处理 超时配置 重试策略 降级方案 日志记录 监控告警

这些属于后面的工程化内容。


三十、不要把 Redis API 当成本地方法调用

下面这段代码看起来很普通:

stringRedisTemplate.opsForValue() .set("user:name", "张三");

但它本质上不是简单的本地赋值。

本地赋值:

userName = "张三";

只发生在当前 JVM 中。

Redis 操作则包含:

序列化 连接获取 协议编码 网络传输 服务端执行 结果返回

所以在设计代码时,应当意识到:

每一次 Redis 操作,本质上都是一次对外部数据服务的访问。

这意味着不能毫无节制地在循环中频繁调用 Redis。

例如:

for (Long userId : userIds) { String value = stringRedisTemplate .opsForValue() .get("user:" + userId); }

如果userIds有 1000 个,就可能产生大量 Redis 请求。

后面需要学习:

批量操作 Pipeline 合理的数据结构设计 减少网络往返

三十一、Redis 快,不等于调用没有成本

Redis 主要操作内存,因此处理单条简单命令通常很快。

但一次完整调用仍然可能包含:

Java 方法调用 序列化 客户端排队 网络发送 Redis 执行 网络返回 反序列化

如果每个业务接口都随意发送几十次甚至上百次 Redis 请求,性能仍然可能受到影响。

所以 Redis 使用的核心不是:

反正 Redis 快,随便调用

而是:

选择合适的数据结构 设计清晰的 Key 减少无意义的请求 控制数据大小 合理设置过期时间

三十二、重新理解 RedisTemplate

现在可以重新理解RedisTemplate

它不是:

保存 Redis 数据的容器

而是:

Spring Boot 进程中用于操作 Redis 的客户端模板和高级封装。

它主要帮助我们完成:

选择 Redis 数据结构 序列化 Key 和 Value 获取连接 执行底层命令 转换返回结果 统一异常处理

而真正的数据仍然保存在:

Redis Server 进程

所以:

RedisTemplate 重建 → Redis 数据不会因此消失 Spring Boot 重启 → Redis 数据通常仍由 Redis Server 保管 Redis Server 被清空 → Java 中的 RedisTemplate 无法恢复这些数据

三十三、本篇总结

这一篇沿着一条SET命令,分析了 Java 操作 Redis 的完整过程。

我们写下:

stringRedisTemplate.opsForValue() .set("user:name", "张三");

之后,主要经历了以下步骤:

1. 业务代码调用 StringRedisTemplate 2. Spring Data Redis 处理操作请求 3. Key 和 Value 被序列化成字节 4. 底层 Redis 客户端获取连接 5. 客户端生成并编码 SET 命令 6. 命令通过 TCP Socket 发送 7. Redis Server 接收并解析命令 8. Redis 修改自己管理的内存数据 9. Redis 返回执行结果 10. Java 客户端接收并转换结果

这里最需要记住的是:

Java 业务代码 → 表达操作意图 StringRedisTemplate → 提供 Java 操作接口 Spring Data Redis → 提供统一封装 Redis 客户端 → 负责连接与通信 Redis Server → 真正执行命令并保存数据

最终可以用一句话概括:

Java 调用 Redis API,并不是直接修改 Redis 内存,而是通过 Redis 客户端将命令编码后经 TCP 发送给 Redis Server,由 Redis Server 执行命令、修改自己的数据,再将结果返回给 Java。


下一篇预告

下一篇继续进入 Redis 最基础的数据模型:

《Redis 的 Key-Value 模型到底是什么?Key 应该怎么设计?》

下一篇会重点讲清楚:

Redis 的 Key 和 Value 分别是什么 为什么 Redis Key 通常使用冒号分隔 项目名、业务名和唯一标识如何组合 多个项目共用 Redis 时如何避免冲突 Key 太长或太短分别有什么问题 为什么不能把 Redis 当成 MySQL 模糊查询 如何为用户、Token、验证码和缓存设计 Key

下一篇开始,我们将正式进入 Redis 命令和数据设计阶段。