SpringBoot 整合 Redis 缓存实战详解

在现代后端开发中,缓存是提升系统并发能力、减少数据库压力的核心手段。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 的代码。核心流程可总结为:

  1. 引入 cache + redis 核心依赖;
  2. 配置 Redis 连接与缓存全局参数;
  3. 添加 @EnableCaching 开启缓存;
  4. 自定义 JSON 序列化优化缓存存储;
  5. 通过 @Cacheable、@CachePut、@CacheEvict 实现缓存增删改查。

该方案可直接应用于生产项目,有效降低数据库 QPS,大幅提升接口响应速度和系统并发能力。


作 者:南烛
链 接:https://www.itnotes.top/archives/1433
来 源:IT笔记
文章版权归作者所有,转载请注明出处!


上一篇
下一篇