一、前言:为什么用 spring data redis?
你是否还在手动管理 jedis 连接池?
- 是否为每个 redis 操作写重复的
try-finally代码? - 是否希望像操作数据库一样,用声明式方式操作 redis?
- spring data redis 正是为解决这些问题而生!
作为 spring 官方提供的 redis 集成模块,它:
- 自动管理连接(默认使用高性能 lettuce 客户端)
- 提供
redistemplate和stringredistemplate简化操作 - 支持序列化定制、事务、管道等高级特性
- 无缝集成 spring cache,一行注解实现缓存
本文将带你从零搭建项目,掌握核心 api,并写出优雅的 redis 代码!
二、环境准备
1. 创建 spring boot 项目(2.7+ 或 3.x)
通过 start.spring.io 添加依赖:
- spring web
- spring data redis (access+driver)
或手动添加 maven 依赖:
<dependency>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter-data-redis</artifactid>
</dependency>
<!-- 若使用 spring boot 3.x,无需额外引入 lettuce -->注意:spring boot 2.x 默认使用 lettuce(非阻塞、线程安全),不再推荐 jedis。
2. 启动本地 redis
# 使用 docker 快速启动 docker run -d --name redis -p 6379:6379 redis:7.0
三、基础配置:application.yml
spring:
redis:
host: localhost
port: 6379
password: "" # 无密码留空
database: 0
timeout: 2000ms # 连接超时
lettuce:
pool:
max-active: 20 # 最大连接数
max-idle: 10 # 最大空闲连接
min-idle: 2 # 最小空闲连接
max-wait: 2000ms # 获取连接最大等待时间spring boot 会自动配置 redisconnectionfactory 和 redistemplate,无需手动创建连接池!
四、核心操作:redistemplate vs stringredistemplate
spring data redis 提供两个核心模板类:
| 模板类 | key/value 类型 | 适用场景 |
|---|---|---|
| redistemplate<k, v> | 泛型(object) | 存储 java 对象(需序列化) |
| stringredistemplate | string / string | 纯字符串操作(如验证码、计数器) |
1. 使用 stringredistemplate(推荐初学者)
@restcontroller
public class rediscontroller {
@autowired
private stringredistemplate stringredistemplate;
@getmapping("/set")
public string set(@requestparam string key, @requestparam string value) {
stringredistemplate.opsforvalue().set(key, value, 10, timeunit.minutes);
return "ok";
}
@getmapping("/get")
public string get(@requestparam string key) {
return stringredistemplate.opsforvalue().get(key);
}
// hash 操作
@postmapping("/user")
public void saveuser(@requestparam string userid,
@requestparam string name,
@requestparam integer age) {
stringredistemplate.opsforhash().put("user:" + userid, "name", name);
stringredistemplate.opsforhash().put("user:" + userid, "age", age.tostring());
}
// list 操作
@postmapping("/task")
public void addtask(@requestparam string task) {
stringredistemplate.opsforlist().leftpush("tasks", task);
}
}优点:api 清晰,opsforxxx() 对应 redis 数据类型
2. 使用 redistemplate 存储 java 对象
步骤 1:定义实体类
public class user implements serializable {
private string id;
private string name;
private int age;
// getter/setter...
}步骤 2:配置序列化方式(避免乱码)
@configuration
public class redisconfig {
@bean
public redistemplate<string, object> redistemplate(redisconnectionfactory factory) {
redistemplate<string, object> template = new redistemplate<>();
template.setconnectionfactory(factory);
// 使用 jackson 序列化对象(可读性强)
jackson2jsonredisserializer<object> serializer =
new jackson2jsonredisserializer<>(object.class);
objectmapper mapper = new objectmapper();
mapper.setvisibility(propertyaccessor.all, jsonautodetect.visibility.any);
mapper.activatedefaulttyping(mapper.getpolymorphictypevalidator(),
objectmapper.defaulttyping.non_final);
serializer.setobjectmapper(mapper);
// 设置 key 和 value 的序列化方式
template.setkeyserializer(new stringredisserializer());
template.setvalueserializer(serializer);
template.sethashkeyserializer(new stringredisserializer());
template.sethashvalueserializer(serializer);
template.afterpropertiesset();
return template;
}
}步骤 3:操作对象
@autowired
private redistemplate<string, object> redistemplate;
public void saveuser(user user) {
redistemplate.opsforvalue().set("user:" + user.getid(), user, 1, timeunit.hours);
}
public user getuser(string id) {
return (user) redistemplate.opsforvalue().get("user:" + id);
}提示:若不配置序列化,默认使用 jdk 序列化,会导致 redis 中出现不可读的二进制数据。
五、常用操作速查表
| 操作 | 代码示例 |
|---|---|
| string | opsforvalue().set("k", "v") |
| hash | opsforhash().put("user:1", "name", "张三") |
| list | opsforlist().rightpush("queue", "item") |
| set | opsforset().add("tags", "java", "redis") |
| zset | opsforzset().add("rank", "playera", 95.5) |
| 过期时间 | expire("key", 60, timeunit.seconds) |
| 批量操作 | opsforvalue().multiset(map) |
六、进阶:结合 spring cache 实现声明式缓存
只需三步,方法结果自动缓存!
1. 启用缓存
@springbootapplication
@enablecaching // ← 关键注解
public class application {
public static void main(string[] args) {
springapplication.run(application.class, args);
}
}2. 在 service 方法上加注解
@service
public class userservice {
@cacheable(value = "users", key = "#id")
public user getuserbyid(string id) {
system.out.println("查询数据库..."); // 仅首次打印
return usermapper.selectbyid(id);
}
@cacheevict(value = "users", key = "#id")
public void updateuser(user user) {
usermapper.update(user);
}
}效果:
- 第一次调用
getuserbyid("1001")→ 查询 db 并缓存 - 后续调用 → 直接返回缓存,不执行方法体
七、常见问题与避坑指南
坑 1:redis 中出现\xac\xed\x00\x05乱码
原因:使用了默认的 jdk 序列化
解决:配置 stringredisserializer 或 jackson2jsonredisserializer
坑 2:缓存穿透(大量查不存在的 key)
方案:对 null 结果也缓存(短 ttl),或使用布隆过滤器
坑 3:缓存雪崩(大量 key 同时过期)
方案:设置随机过期时间,如 600 + random(60)
八、jedis vs lettuce vs spring data redis
| 方案 | 适用场景 |
|---|---|
| 原生 jedis | 学习 redis 协议、极简项目 |
| jedispool | 需要精细控制连接池的中小项目 |
| spring data redis (lettuce) | ✅ 主流选择:spring boot 项目、高并发、响应式支持 |
建议:新项目直接使用 spring data redis + lettuce
九、总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。
发表评论