引言
前两篇已经建立了 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 → 访问 Redis4. Redis 客户端
真正负责与 Redis Server 建立网络连接的,是底层 Redis 客户端。
Java 中常见的 Redis 客户端包括:
Lettuce Jedis RedissonSpring Boot 项目中,我们可能只直接使用StringRedisTemplate,但在更底层,仍然需要具体客户端负责:
建立连接 发送命令 接收响应 处理网络异常 管理连接状态整体关系可以理解为:
StringRedisTemplate → Spring Data Redis → Lettuce 或其他客户端 → Redis Server5. 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 ZSetSpring 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 方法 |
| Retrofit | Spring Data Redis |
| OkHttp | Lettuce、Jedis 等客户端 |
| HTTP 请求格式 | Redis 协议格式 |
| Spring Boot Server | Redis 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:6379TCP 负责把字节从客户端可靠地传输到 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:nameRedis 也会返回参数错误。
因此 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 ServerMaven 或 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:6379A 执行:
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 原本不存在:
删除数量:0Spring 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 命令和数据设计阶段。