前言
在 Java Web 开发中,Redis 是高频使用的缓存中间件,它能极大提升系统性能、减轻数据库压力。今天这篇学习日记,我会带着大家从 0 到 1 实现 SpringBoot 整合 Redis,不仅会讲基础的配置和 API 使用,还会结合实战场景讲解缓存的核心用法,新手也能跟着敲完就用。
一、前置准备
1. 环境要求
- Redis 服务:本地安装 Redis(推荐 5.x/6.x 版本)或使用云服务器 Redis
- 测试工具:Redis Desktop Manager(可视化工具,可选)、Postman(接口测试)
- SpringBoot 版本:2.7.12(和前文保持一致,避免版本兼容问题)
2. 核心依赖引入(pom.xml)
SpringBoot 提供了spring-boot-starter-data-redis依赖,能快速整合 Redis,无需手动引入繁杂的客户端依赖:
xml
XML
<!-- Redis核心依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- 连接池依赖(提升Redis连接性能,必加) -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<!-- lombok(简化代码,可选) -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
二、核心配置:Redis 连接与自定义配置
1. 基础连接配置(application.yml)
在src/main/resources下创建 / 修改application.yml,配置 Redis 连接信息:
yaml
spring:
# Redis配置
redis:
# 服务器地址(本地默认127.0.0.1)
host: 127.0.0.1
# 端口(默认6379)
port: 6379
# 密码(无密码则注释)
# password: 123456
# 数据库索引(Redis默认有16个库,从0开始)
database: 0
# 连接超时时间
timeout: 10000ms
# 连接池配置
lettuce:
pool:
# 最大活跃连接数
max-active: 8
# 最大空闲连接数
max-idle: 8
# 最小空闲连接数
min-idle: 0
# 最大等待时间(-1表示无限制)
max-wait: -1ms
2. 自定义 RedisTemplate 配置(关键)
SpringBoot 默认提供的RedisTemplate使用JdkSerializationRedisSerializer序列化,存到 Redis 的 key/value 会是乱码,因此需要自定义配置,改用Jackson2JsonRedisSerializer实现 JSON 序列化:
java
运行
java
package com.java.diary.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
// 定义RedisTemplate对象
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
// 设置连接工厂
redisTemplate.setConnectionFactory(factory);
// 1. 创建JSON序列化器
Jackson2JsonRedisSerializer<Object> jacksonSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper om = new ObjectMapper();
// 开启所有字段的序列化
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
// 支持JDK8日期类型
om.findAndRegisterModules();
jacksonSerializer.setObjectMapper(om);
// 2. 创建String序列化器(key和hashKey用String)
StringRedisSerializer stringSerializer = new StringRedisSerializer();
// 3. 配置序列化规则
redisTemplate.setKeySerializer(stringSerializer); // key序列化
redisTemplate.setHashKeySerializer(stringSerializer); // hash的key序列化
redisTemplate.setValueSerializer(jacksonSerializer); // value序列化
redisTemplate.setHashValueSerializer(jacksonSerializer); // hash的value序列化
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}
核心说明:
StringRedisSerializer:保证 Redis 中的 key 是清晰的字符串,而非乱码;Jackson2JsonRedisSerializer:将 Java 对象序列化为 JSON 字符串存储,方便查看和解析;- 配置后,Redis 中存储的内容可读性强,且能正确反序列化为 Java 对象。
三、核心实战:Redis API 全场景使用
SpringBoot 操作 Redis 主要有两种方式:
RedisTemplate:通用型 API,支持所有 Redis 数据类型(String、Hash、List、Set、ZSet);StringRedisTemplate:简化版,专门处理 String 类型(底层也是 RedisTemplate,序列化方式固定为 String)。
1. 封装 Redis 工具类(企业级实战)
实际开发中,建议封装工具类统一管理 Redis 操作,避免重复代码:
java
运行
java
package com.java.diary.util;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
@Component
@RequiredArgsConstructor // 构造器注入(替代@Autowired)
public class RedisUtil {
private final RedisTemplate<String, Object> redisTemplate;
// ==================== String类型操作 ====================
/**
* 设置缓存
* @param key 键
* @param value 值
* @param timeout 过期时间(秒)
*/
public void set(String key, Object value, long timeout) {
redisTemplate.opsForValue().set(key, value, timeout, TimeUnit.SECONDS);
}
/**
* 设置缓存(无过期时间)
*/
public void set(String key, Object value) {
redisTemplate.opsForValue().set(key, value);
}
/**
* 获取缓存
*/
public Object get(String key) {
return key == null ? null : redisTemplate.opsForValue().get(key);
}
/**
* 删除缓存
*/
public Boolean delete(String key) {
return redisTemplate.delete(key);
}
/**
* 设置过期时间
*/
public Boolean expire(String key, long timeout) {
return redisTemplate.expire(key, timeout, TimeUnit.SECONDS);
}
// ==================== Hash类型操作(示例) ====================
/**
* Hash设置值
*/
public void hSet(String key, String hashKey, Object value) {
redisTemplate.opsForHash().put(key, hashKey, value);
}
/**
* Hash获取值
*/
public Object hGet(String key, String hashKey) {
return redisTemplate.opsForHash().get(key, hashKey);
}
}
2. 实体类准备(测试对象存储)
java
运行
java
package com.java.diary.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable; // 必须实现序列化接口(Redis存储对象要求)
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User implements Serializable {
private Integer id;
private String name;
private Integer age;
}
3. 实战测试:Controller 调用 Redis
java
运行
java
package com.java.diary.controller;
import com.java.diary.entity.User;
import com.java.diary.util.RedisUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;
@Slf4j
@RestController
@RequestMapping("/redis")
@RequiredArgsConstructor
public class RedisController {
private final RedisUtil redisUtil;
// 1. 测试String类型 - 存储普通字符串
@GetMapping("/set/string")
public Map<String, Object> setString() {
redisUtil.set("test:str", "Hello Redis!", 60); // 60秒过期
Map<String, Object> result = new HashMap<>();
result.put("code", 200);
result.put("msg", "字符串存储成功");
return result;
}
// 2. 测试String类型 - 获取普通字符串
@GetMapping("/get/string")
public Map<String, Object> getString() {
String value = (String) redisUtil.get("test:str");
Map<String, Object> result = new HashMap<>();
result.put("code", 200);
result.put("data", value);
return result;
}
// 3. 测试存储Java对象
@PostMapping("/set/user")
public Map<String, Object> setUser(@RequestBody User user) {
String key = "test:user:" + user.getId();
redisUtil.set(key, user, 300); // 5分钟过期
Map<String, Object> result = new HashMap<>();
result.put("code", 200);
result.put("msg", "用户对象存储成功");
return result;
}
// 4. 测试获取Java对象
@GetMapping("/get/user/{id}")
public Map<String, Object> getUser(@PathVariable Integer id) {
String key = "test:user:" + id;
User user = (User) redisUtil.get(key);
Map<String, Object> result = new HashMap<>();
result.put("code", 200);
result.put("data", user);
return result;
}
// 5. 测试Hash类型
@GetMapping("/test/hash")
public Map<String, Object> testHash() {
String key = "test:hash:user";
redisUtil.hSet(key, "name", "李四");
redisUtil.hSet(key, "age", 28);
String name = (String) redisUtil.hGet(key, "name");
Integer age = (Integer) redisUtil.hGet(key, "age");
Map<String, Object> result = new HashMap<>();
result.put("code", 200);
result.put("data", "name=" + name + ", age=" + age);
return result;
}
}
4. 测试步骤
- 启动 Redis 服务(本地执行
redis-server); - 启动 SpringBoot 项目;
- 接口测试:
-
存储字符串:
http://localhost:8080/redis/set/string -
获取字符串:
http://localhost:8080/redis/get/string -
存储用户对象:Postman 发送 POST 请求
http://localhost:8080/redis/set/user,请求体:json
{ "id": 1, "name": "张三", "age": 25 } -
获取用户对象:
http://localhost:8080/redis/get/user/1 -
Hash 测试:
http://localhost:8080/redis/test/hash
-
四、进阶场景:结合业务的缓存使用
1. 缓存 + 数据库(查询场景)
java
运行
java
// 模拟Service层
@Service
@RequiredArgsConstructor
public class UserService {
private final RedisUtil redisUtil;
// 模拟数据库操作(实际项目注入Mapper/Repository)
/**
* 查询用户(先查缓存,缓存无则查库,再存缓存)
*/
public User getUserById(Integer id) {
String key = "user:info:" + id;
// 1. 先查缓存
User user = (User) redisUtil.get(key);
if (user != null) {
log.info("从缓存获取用户:{}", id);
return user;
}
// 2. 缓存无,查数据库(模拟查询)
log.info("从数据库获取用户:{}", id);
user = new User(id, "数据库用户", 30);
// 3. 存入缓存(设置过期时间,避免缓存永久有效)
redisUtil.set(key, user, 300);
return user;
}
}
2. 缓存更新 / 删除(修改 / 删除场景)
java
运行
java
/**
* 更新用户(更新数据库后,删除缓存)
*/
public void updateUser(User user) {
// 1. 更新数据库(模拟)
log.info("更新数据库用户:{}", user);
// 2. 删除缓存(缓存更新策略:先更库,再删缓存,避免缓存脏数据)
String key = "user:info:" + user.getId();
redisUtil.delete(key);
}
五、避坑指南
- 对象序列化问题 :存储 Java 对象时,实体类必须实现
Serializable接口,否则会抛出序列化异常; - 缓存过期时间:生产环境务必给缓存设置过期时间,避免 Redis 内存溢出;
- key 命名规范 :建议用
业务名:模块名:id的格式(如user:info:1),方便管理和排查; - 连接池配置 :必须引入
commons-pool2依赖,否则连接池配置不生效,影响性能; - 缓存穿透 / 击穿 / 雪崩 :
- 穿透:缓存和数据库都无数据,可缓存空值;
- 击穿:热点 key 过期瞬间大量请求打向数据库,可设置热点 key 永不过期;
- 雪崩:大量 key 同时过期,可给过期时间加随机值。
总结
- SpringBoot 整合 Redis 核心依赖是
spring-boot-starter-data-redis,配合连接池依赖可提升连接性能; - 自定义
RedisTemplate的序列化方式(String+JSON)是关键,能解决默认序列化乱码问题; - 实际开发中建议封装 Redis 工具类,业务层遵循 "先查缓存,再查数据库,查库后更新缓存" 的核心逻辑,同时注意设置过期时间、规范 key 命名,避免缓存问题。
今天的学习重点是 Redis 的基础整合和实战用法,后续会深入讲解 Redis 缓存注解(@Cacheable等)、分布式锁等进阶知识点,一起把 Redis 用透~