一、前言
很多新手学Redis String会乱用API,导致缓存失效、内存浪费、业务出错。本篇文章我们将贴合实际开发场景, 全程使用SpringBoot原生RedisTemplate编写示例,从核心特性、底层逻辑、API实操、高频场景到避坑指南,一站式讲透,新手看完就能直接用到项目里。
二、Redis String到底是什么?
Redis String(字符串)是Redis最基础的键值对存储类型,它的本质是 二进制安全的简单动态字符串(SDS) ,不同于Java中的String,它可以存储任意类型的数据,不仅是普通文本,还能存储数字、图片、序列化后的对象、字节数组等,最大单次存储容量为512MB ,这也是它应用广泛的核心原因。
三、String核心特性
- **二进制安全 :**不会因为特殊字符、字节码导致数据截断,存储内容无格式限制;
- **支持数值运算 :**存储的数字可以直接做自增、自减操作,不用手动取出计算再存回;
- **读写效率极高 :**内存存储,单key读写时间复杂度O(1),毫秒级响应;
- **兼容SpringBoot无缝对接 :**RedisTemplate提供专属opsForValue()接口,专门操作String类型。
四、工作中高频使用场景
String虽然简单,但覆盖了后端开发80%的Redis缓存场景,最常见的有:
- 手机/邮箱验证码存储(带过期时间);
- 用户登录会话、Token缓存;
- 接口访问计数器、商品销量、文章阅读量统计;
- 简单单体对象缓存(用户基础信息、商品基础信息);
- 分布式锁、接口限流标记。
五、SpringBoot依赖与基础配置
实操前先完成基础配置,确保RedisTemplate正常使用,这是后续所有代码运行的前提,配置极简,新手直接复制即可。
1、引入Maven依赖
java
<!-- SpringBoot Redis核心依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- 连接池依赖,避免连接耗尽 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
2、application.yml基础配置
java
spring:
redis:
host: 127.0.0.1 # Redis服务器IP
port: 6379 # 端口
password: # 有密码则填写,无密码留空
database: 0 # 默认使用0号库
lettuce:
pool:
max-active: 8 # 最大连接数
max-idle: 8 # 最大空闲连接
min-idle: 0 # 最小空闲连接
3、注入RedisTemplate
在需要使用的类中,直接注入Spring提供的原生RedisTemplate,无需自定义:
java
@RestController
@RequestMapping("/redis/string")
public class RedisStringController {
// 直接注入原生RedisTemplate,不封装工具类
@Resource
private RedisTemplate<String, Object> redisTemplate;
}
关键提示 : 操作String类型,统一使用redisTemplate.opsForValue() 调用对应API,这是Spring专门为String类型提供的操作接口,也是本文全程使用的核心方法。
六、核心API实操
所有示例均为原生API调用,无任何二次封装,代码简洁易懂,贴合实际开发写法,按场景分类整理,直接复制到Controller即可测试。
1、基础赋值与取值(最常用)
对应Redis原生set、get命令,是String最核心的操作,用于存储普通字符串、数字等简单数据。
java
/**
* 普通赋值:存储字符串
* @param key 键
* @param value 值
*/
@GetMapping("/set")
public String setString(String key, String value) {
// 赋值,无过期时间,永久有效
redisTemplate.opsForValue().set(key, value);
return "赋值成功";
}
/**
* 普通取值:根据key获取值
* @param key 键
* @return 值
*/
@GetMapping("/get")
public Object getString(String key) {
return redisTemplate.opsForValue().get(key);
}
实操示例:调用/redis/string/set?key=username&value=zhangsan,再调用/redis/string/get?key=username,直接返回zhangsan。
2、带过期时间的赋值(高频业务场景)
验证码、临时Token、临时缓存必须设置过期时间,避免Redis内存堆积,这是工作中最常用的写法。
java
/**
* 赋值并设置过期时间(验证码、Token专用)
* @param key 键
* @param value 值
* @param time 过期时间,单位秒
*/
@GetMapping("/setEx")
public String setStringWithExpire(String key, String value, long time) {
// 三个参数:key、value、过期时间、时间单位
redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
return "带过期时间赋值成功";
}
实操示例:存储5分钟有效期的手机验证码,调用/redis/string/setEx?key=phone:code:13800138000&value=6688&time=300,300秒后key自动过期删除。
3、数值自增/自减(计数器专用)
String类型支持存储数字,并直接做原子性自增、自减操作,不用取出再计算,避免并发下计数错误,常用于阅读量、销量、接口限流。
java
/**
* 数值自增(阅读量+1、销量+1)
* @param key 计数器键
* @return 自增后结果
*/
@GetMapping("/incr")
public Long increment(String key) {
// 自增1,原子操作,并发安全
return redisTemplate.opsForValue().increment(key);
}
/**
* 数值自减
* @param key 计数器键
* @return 自减后结果
*/
@GetMapping("/decr")
public Long decrement(String key) {
// 自减1
return redisTemplate.opsForValue().decrement(key);
}
/**
* 自定义步长自增(比如每次+5)
* @param key 键
* @param step 步长
* @return 结果
*/
@GetMapping("/incrBy")
public Long incrementByStep(String key, long step) {
return redisTemplate.opsForValue().increment(key, step);
}
核心优势:increment/decrement是原子操作,多线程并发调用也不会出现计数错误,比手动get再set安全太多。
4、不存在则赋值(防覆盖,分布式锁基础)
对应Redis原生setnx命令,只有key不存在时才赋值,已存在则不操作,避免覆盖已有数据,是实现分布式锁的核心API。
java
/**
* 不存在则赋值,已存在则不操作
* @param key 键
* @param value 值
* @return true=赋值成功,false=key已存在
*/
@GetMapping("/setIfAbsent")
public Boolean setIfAbsent(String key, String value) {
return redisTemplate.opsForValue().setIfAbsent(key, value);
}
5、追加内容、获取剩余过期时间
java
/**
* 追加字符串到原有值后面
*/
@GetMapping("/append")
public Integer append(String key, String value) {
return redisTemplate.opsForValue().append(key, value);
}
/**
* 获取key剩余过期时间(秒)
*/
@GetMapping("/getTtl")
public Long getTtl(String key) {
return redisTemplate.getExpire(key, TimeUnit.SECONDS);
}
七、实战案例:实现验证码存储
结合实际业务,用上面的API实现一个完整的手机验证码存储功能,覆盖赋值、过期、校验全流程,无封装、无冗余代码,直接适配项目。
java
/**
* 发送手机验证码,存储到Redis,5分钟有效期
*/
@GetMapping("/sendCode")
public String sendPhoneCode(String phone) {
// 生成6位随机验证码
String code = String.valueOf((int)((Math.random() * 9 + 1) * 100000));
// 拼接key,规范命名:业务前缀:手机号
String key = "login:code:" + phone;
// 存入Redis,5分钟过期
redisTemplate.opsForValue().set(key, code, 300, TimeUnit.SECONDS);
// 实际项目中此处调用短信SDK发送验证码
return "验证码发送成功,5分钟内有效,验证码:" + code;
}
/**
* 校验验证码是否正确
*/
@GetMapping("/checkCode")
public String checkCode(String phone, String code) {
String key = "login:code:" + phone;
String cacheCode = (String) redisTemplate.opsForValue().get(key);
if (cacheCode == null) {
return "验证码已过期,请重新获取";
}
if (cacheCode.equals(code)) {
// 校验成功后删除验证码,防止重复使用
redisTemplate.delete(key);
return "验证码校验成功";
}
return "验证码错误,请重新输入";
}
这个案例是电商、后台管理系统的通用写法,完全贴合生产环境,没有多余操作,新手直接复用即可。
八、新手必避坑:String使用高频误区
很多开发者用String经常踩坑,导致线上问题,这几个坑一定要牢记:
- **禁止存储超大内容 :**String最大支持512MB,但实际开发中,单个key值严禁超过10KB,大内容会导致Redis内存暴涨、网络IO阻塞,大对象建议用Hash或拆分存储;
- **禁止不设置过期时间 :**除了永久缓存,所有业务缓存、临时数据必须设置过期时间,否则Redis内存会被占满,引发OOM;
- **禁止用普通set实现分布式锁 :**分布式锁必须用setIfAbsent+过期时间,普通set会导致锁无法释放、死锁;
- **key命名不规范 :**禁止用单字符、中文做key,建议用"业务模块:功能:唯一标识"格式,比如:user:info:1001、order:token:2024001;
- **滥用increment存非数字 :**increment只能操作存储数字的key,操作字符串会直接报错;
- **忽略序列化问题 :**RedisTemplate默认序列化会出现乱码,生产环境建议自定义String和Value序列化方式,避免数据异常。