在现代后端开发中,缓存是提升系统并发能力、减少数据库压力的核心手段。SpringBoot 对 Redis 缓存提供了自动化集成方案,结合 Spring 缓存抽象注解,可以快速实现接口数据缓存、过期淘汰、缓存更新等常用功能。本文将从零开始,完整讲解 SpringBoot 整合 Redis 实现缓存功能的全过程,包含环境配置、基础使用、进阶优化及避坑要点。
一、技术栈与环境准备
1. 核心技术版本
- SpringBoot:2.7.x / 3.x(适配主流版本)
- Redis:5.0+(支持持久化、过期策略)
- Maven/Gradle:项目构建工具
- Spring Cache:Spring 官方缓存抽象,统一缓存注解
2. 前置环境
本地或服务器已安装 Redis 服务,且服务正常启动,默认端口 6379,无特殊密码或配置好对应密码、远程访问权限。
二、引入项目依赖
SpringBoot 整合 Redis 缓存需要两个核心依赖:spring-boot-starter-data-redis(Redis 操作核心依赖)、spring-boot-starter-cache(Spring 缓存注解支持)。
Maven 依赖(pom.xml)
<!-- Spring 缓存核心依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<!-- Redis 操作依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- 序列化工具(解决对象缓存序列化问题) -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
三、全局配置(application.yml)
在配置文件中配置 Redis 连接信息、超时时间、连接池参数,适配生产环境使用,避免连接耗尽问题。
spring:
# Redis 配置
redis:
# Redis 服务器地址
host: localhost
# Redis 端口
port: 6379
# Redis 密码(无密码则注释)
# password: 123456
# 选择的数据库(Redis 默认16个数据库,0-15)
database: 0
# 连接超时时间
timeout: 10000ms
# 连接池配置
lettuce:
pool:
# 最大活跃连接数
max-active: 8
# 最大空闲连接
max-idle: 8
# 最小空闲连接
min-idle: 2
# 最大等待时间(-1 表示无限制)
max-wait: -1ms
# 缓存全局配置
cache:
# 指定缓存类型为 Redis
type: redis
# 缓存默认过期时间(单位:秒,此处10分钟)
redis:
time-to-live: 600s
# 是否缓存空值(防止缓存穿透)
cache-null-values: true
# 开启键前缀,区分不同项目缓存
key-prefix: spring_boot_cache:
四、开启缓存功能
在 SpringBoot 启动类上添加 @EnableCaching 注解,开启全局缓存注解支持,这是缓存生效的核心配置。
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
@SpringBootApplication
@EnableCaching // 开启缓存功能
public class RedisCacheApplication {
public static void main(String[] args) {
SpringApplication.run(RedisCacheApplication.class, args);
}
}
五、Redis 缓存序列化配置(关键)
SpringBoot 默认使用 JDK 序列化存储缓存数据,存在可读性差、占用空间大、无法跨语言访问等问题。我们自定义配置类,使用 Jackson2JsonRedisSerializer 实现 JSON 序列化,优化缓存存储格式。
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.time.Duration;
import java.util.HashMap;
import java.util.Map;
@Configuration
public class RedisCacheConfig extends CachingConfigurerSupport {
/**
* 自定义缓存 key 生成器(默认类名+方法名+参数)
*/
@Override
@Bean
public KeyGenerator keyGenerator() {
return (target, method, params) -> {
StringBuilder sb = new StringBuilder();
sb.append(target.getClass().getName());
sb.append(".");
sb.append(method.getName());
for (Object param : params) {
sb.append("_").append(param);
}
return sb.toString();
};
}
/**
* 自定义 Redis 缓存管理器(JSON序列化+自定义过期时间)
*/
@Bean
public RedisCacheManager cacheManager(RedisConnectionFactory factory) {
// String 序列化器(key序列化)
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// JSON 序列化器(value序列化)
Jackson2JsonRedisSerializer<Object> jsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
// 识别完整类型,解决泛型序列化问题
objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
jsonRedisSerializer.setObjectMapper(objectMapper);
// 默认缓存配置
RedisCacheConfiguration defaultConfig = RedisCacheConfiguration.defaultCacheConfig()
// 默认过期时间10分钟
.entryTtl(Duration.ofSeconds(600))
// key 使用string序列化
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(stringRedisSerializer))
// value 使用json序列化
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jsonRedisSerializer))
// 禁止缓存空值(可根据业务开启)
.disableCachingNullValues();
// 自定义指定缓存过期时间(不同业务不同过期策略)
Map<String, RedisCacheConfiguration> configMap = new HashMap<>();
configMap.put("userCache", defaultConfig.entryTtl(Duration.ofMinutes(30))); // 用户缓存30分钟
configMap.put("goodsCache", defaultConfig.entryTtl(Duration.ofHours(1))); // 商品缓存1小时
return RedisCacheManager.builder(factory)
.cacheDefaults(defaultConfig)
.withInitialCacheConfigurations(configMap)
.build();
}
}
六、核心缓存注解实战
Spring Cache 提供了四大核心注解,无需手动操作 Redis 模板,即可自动实现缓存新增、查询、更新、删除,简化业务代码。
1. 业务实体类
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User implements Serializable {
private Long id;
private String username;
private Integer age;
private String phone;
}
2. Service 层缓存实战
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
@Service
public class UserService {
/**
* @Cacheable:查询缓存
* 逻辑:先查缓存,存在则直接返回,不存在则执行方法,结果存入缓存
* value:缓存名称(对应配置类自定义的缓存)
* key:缓存key,支持SpEL表达式
*/
@Cacheable(value = "userCache", key = "#id")
public User getUserById(Long id) {
// 模拟查询数据库
System.out.println("执行数据库查询:用户id=" + id);
return new User(id, "张三", 22, "13800138000");
}
/**
* @CachePut:更新缓存
* 逻辑:每次执行方法,强制更新缓存数据,适用于新增/修改场景
*/
@CachePut(value = "userCache", key = "#user.id")
public User updateUser(User user) {
// 模拟数据库更新
System.out.println("执行数据库更新:" + user);
return user;
}
/**
* @CacheEvict:删除缓存
* 逻辑:执行方法后,删除指定缓存
* allEntries=true:清空当前缓存下所有数据
*/
@CacheEvict(value = "userCache", key = "#id")
public void deleteUser(Long id) {
// 模拟数据库删除
System.out.println("执行数据库删除:用户id=" + id);
}
/**
* 清空所有用户缓存
*/
@CacheEvict(value = "userCache", allEntries = true)
public void clearUserCache() {
System.out.println("清空所有用户缓存数据");
}
}
3. 测试接口(Controller)
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@RestController
@RequestMapping("/user")
public class UserController {
@Resource
private UserService userService;
@GetMapping("/get/{id}")
public User getUser(@PathVariable Long id) {
// 第一次请求:查数据库,存入缓存
// 第二次请求:直接读缓存,不执行数据库查询
return userService.getUserById(id);
}
@GetMapping("/update")
public User updateUser() {
User user = new User(1L, "张三更新", 23, "13800138000");
return userService.updateUser(user);
}
@GetMapping("/delete/{id}")
public String deleteUser(@PathVariable Long id) {
userService.deleteUser(id);
return "删除成功";
}
@GetMapping("/clear")
public String clearCache() {
userService.clearUserCache();
return "缓存清空成功";
}
}
七、功能测试与效果验证
1. 查询缓存测试
- 首次访问
/user/get/1:控制台打印数据库查询日志,数据存入 Redis - 再次访问
/user/get/1:无数据库日志,直接读取缓存数据,接口响应速度大幅提升
2. 更新缓存测试
访问更新接口后,Redis 中对应 key 的数据会实时刷新,保证缓存与数据库数据一致性。
3. 删除缓存测试
执行删除接口后,Redis 中对应缓存 key 被清除,下次查询会重新从数据库加载数据。
八、常见问题与优化方案
1. 缓存穿透
问题:查询不存在的数据,直接穿透到数据库,频繁请求会压垮数据库。
解决:配置文件开启 cache-null-values: true,缓存空值,短期拦截无效请求。
2. 缓存过期/雪崩
问题:大量缓存同时过期,瞬间所有请求访问数据库。
解决:给缓存过期时间添加随机偏移量,避免批量过期;核心业务设置永不过期,手动更新。
3. 缓存序列化乱码
问题:Redis 客户端查看缓存数据乱码、格式怪异。
解决:使用本文自定义的 JSON 序列化配置,缓存数据为标准 JSON 格式,可读性强。
4. 缓存与数据库不一致
解决:更新、删除数据时,强制更新或清除对应缓存;核心业务可采用 先更新数据库,再删除缓存 的策略。
九、总结
SpringBoot 整合 Redis 缓存的核心优势是低代码、高复用、易维护,通过 Spring Cache 注解可以彻底解放手动操作 Redis 的代码。核心流程可总结为:
- 引入 cache + redis 核心依赖;
- 配置 Redis 连接与缓存全局参数;
- 添加 @EnableCaching 开启缓存;
- 自定义 JSON 序列化优化缓存存储;
- 通过 @Cacheable、@CachePut、@CacheEvict 实现缓存增删改查。
该方案可直接应用于生产项目,有效降低数据库 QPS,大幅提升接口响应速度和系统并发能力。