SpringCache 缓存使用方案总结

 更新时间:2026年02月25日 10:10:01   作者:Dragon   Wu  
在基于SpringBoot3.x集成JetCache时遇到问题,决定采用SpringCache作为替代方案,本文详细介绍了SpringCache本地缓存(Caffeine)和本地+远程(Redis)混合缓存的配置和使用方法,并总结了常用的缓存注解参数及其含义,感兴趣的朋友跟随小编一起看看吧

近期在基于 SpringBoot 3.x 集成最新版 JetCache 时,发现该组件对 SpringBoot 3.x 的支持并不完善。最突出的问题是:使用 @Cached 注解配置本地缓存时,以变量作为缓存 key 的方式完全不生效,经过多轮排查和资料查阅后仍未找到有效解决方案。因此,我最终决定采用 SpringCache 作为替代方案,该方案能够与 SpringBoot 3.x 完美兼容。

一、纯本地缓存(Caffeine)完整版

1)依赖(正确版)

<dependencies>
    <!-- Spring Cache 核心 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-cache</artifactId>
    </dependency>
    <!-- Caffeine 本地缓存 -->
    <dependency>
        <groupId>com.github.ben-manes.caffeine</groupId>
        <artifactId>caffeine</artifactId>
    </dependency>
</dependencies>

2)配置类(直接用)

import com.github.benmanes.caffeine.cache.Caffeine;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.caffeine.CaffeineCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.concurrent.TimeUnit;
@Configuration
@EnableCaching // 开启缓存
public class LocalCacheConfig {
    @Bean
    public CaffeineCacheManager cacheManager() {
        CaffeineCacheManager manager = new CaffeineCacheManager();
        manager.setCaffeine(Caffeine.newBuilder()
                .expireAfterWrite(60, TimeUnit.SECONDS) // 缓存60秒过期
                .maximumSize(10000)                   // 最多存1万条
        );
        return manager;
    }
}

3)本地缓存 · 增删改查(带参数解释)

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 SysUserService {
    // ==================== 查询 ====================
    /**
     * @Cacheable 查询缓存:先查缓存,没有才执行方法
     * value      = 缓存名称(必须)
     * key        = 缓存key,#p0 = 第一个参数
     * unless     = 结果为null时不缓存(防穿透)
     * sync       = true 并发只放一个请求查库(防击穿)
     */
    @Cacheable(value = "sysUser", key = "#p0", unless = "#result == null", sync = true)
    public SysUserDetailResponse getUserById(Long userId) {
        System.out.println("查询数据库");
        return new SysUserDetailResponse();
    }
    // ==================== 新增 ====================
    /**
     * @CachePut 新增/更新缓存:方法一定执行,结果写入缓存
     * key = #result.id 用返回对象的id做缓存key
     */
    @CachePut(value = "sysUser", key = "#result.id", unless = "#result == null")
    public SysUserDetailResponse createUser(SysUserAddRequest request) {
        System.out.println("新增数据库");
        SysUserDetailResponse user = new SysUserDetailResponse();
        user.setId(100L);
        return user;
    }
    // ==================== 修改 ====================
    @CachePut(value = "sysUser", key = "#p0.id", unless = "#result == null")
    public SysUserDetailResponse updateUser(SysUserUpdateRequest request) {
        System.out.println("修改数据库");
        return new SysUserDetailResponse();
    }
    // ==================== 删除 ====================
    /**
     * @CacheEvict 删除缓存
     * allEntries = false(默认)删单个key
     */
    @CacheEvict(value = "sysUser", key = "#p0")
    public void deleteUser(Long userId) {
        System.out.println("删除数据库");
    }
    // 清空整个缓存
    @CacheEvict(value = "sysUser", allEntries = true)
    public void clearAllUserCache() {
    }
}

二、本地 + 远程(Redis)混合缓存完整版

1)依赖

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-cache</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    <dependency>
        <groupId>com.github.ben-manes.caffeine</groupId>
        <artifactId>caffeine</artifactId>
    </dependency>
</dependencies>

2)application.yml

spring:
  redis:
    host: 127.0.0.1
    port: 6379
    database: 0

3)混合缓存配置(本地优先 → Redis)

import com.github.benmanes.caffeine.cache.Caffeine;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.caffeine.CaffeineCache;
import org.springframework.cache.support.CompositeCacheManager;
import org.springframework.cache.support.SimpleCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.util.List;
import java.util.concurrent.TimeUnit;
@Configuration
@EnableCaching
public class HybridCacheConfig {
    // 本地缓存
    @Bean
    public SimpleCacheManager localCacheManager() {
        SimpleCacheManager manager = new SimpleCacheManager();
        manager.setCaches(List.of(new CaffeineCache("sysUser",
            Caffeine.newBuilder()
                .expireAfterWrite(60, TimeUnit.SECONDS)
                .maximumSize(10000)
                .build()
        )));
        return manager;
    }
    // Redis缓存
    @Bean
    public RedisCacheManager redisCacheManager(RedisConnectionFactory factory) {
        var serializer = new GenericJackson2JsonRedisSerializer();
        var config = org.springframework.data.redis.cache.RedisCacheConfiguration.defaultCacheConfig()
            .entryTtl(java.time.Duration.ofSeconds(300))
            .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
            .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(serializer));
        return RedisCacheManager.builder(factory).cacheDefaults(config).build();
    }
    // 组合:先本地 → 再Redis → 最后数据库
    @Bean
    public CacheManager cacheManager(SimpleCacheManager localCacheManager, RedisCacheManager redisCacheManager) {
        CompositeCacheManager composite = new CompositeCacheManager();
        composite.setCacheManagers(List.of(localCacheManager, redisCacheManager));
        return composite;
    }
}

三、注解所有参数 · 极简解释(一眼看懂)

注解参数核心含义常用值示例
@Cacheablevalue缓存名称(必须,用于隔离不同业务缓存)“sysUser”、“sysRole”
@Cacheablekey缓存唯一标识(SpEL表达式)#p0、#userId、#result.id
@Cacheableunless满足条件时不缓存(防穿透)#result == null
@Cacheablesync并发仅放行一个请求查库(防击穿)true
@CachePutvalue缓存名称“sysUser”
@CachePutkey要更新的缓存key#p0.id、#result.id
@CachePutunless结果为null时不更新缓存#result == null
@CacheEvictkey要删除的缓存key#p0
@CacheEvictallEntries是否清空该缓存下所有key(默认false)true、false

四、最主流、最标准、最推荐的写法(速记版)

// 查询(防穿透+防击穿)
@Cacheable(value = "sysUser", key = "#p0", unless = "#result == null", sync = true)
// 新增(用返回值ID做key)
@CachePut(value = "sysUser", key = "#result.id", unless = "#result == null")
// 修改(用入参ID做key)
@CachePut(value = "sysUser", key = "#p0.id", unless = "#result == null")
// 删除单个key
@CacheEvict(value = "sysUser", key = "#p0")
// 清空整个缓存
@CacheEvict(value = "sysUser", allEntries = true)

五、一页纸速记图(Markdown版)

# Spring Cache 速记表(Spring Boot 3.x)
## 核心依赖
| 缓存类型       | 依赖坐标                                                                 |
|----------------|--------------------------------------------------------------------------|
| 纯本地         | spring-boot-starter-cache + com.github.ben-manes:caffeine                |
| 本地+Redis     | 纯本地依赖 + spring-boot-starter-data-redis                             |
## 核心注解
| 操作   | 注解       | 标准写法                                 | 核心作用                     |
|--------|------------|------------------------------------------|------------------------------|
| 查询   | @Cacheable | @Cacheable(value="sysUser",key="#p0",unless="#result==null",sync=true) | 先查缓存,未命中执行方法     |
| 新增   | @CachePut  | @CachePut(value="sysUser",key="#result.id",unless="#result==null")     | 执行方法后写入缓存           |
| 修改   | @CachePut  | @CachePut(value="sysUser",key="#p0.id",unless="#result==null")        | 执行方法后更新缓存           |
| 删除   | @CacheEvict| @CacheEvict(value="sysUser",key="#p0")                                | 删除指定key缓存              |
| 清空   | @CacheEvict| @CacheEvict(value="sysUser",allEntries=true)                          | 清空该缓存下所有key          |
## 关键参数
| 参数     | 含义                                  | 避坑点                          |
|----------|---------------------------------------|---------------------------------|
| value    | 缓存名称(必须)                      | 不同业务用不同名称,避免冲突    |
| key      | 缓存唯一标识                          | 优先用#p0(参数索引),不报错   |
| unless   | 结果过滤条件                          | 必加#result==null,防缓存穿透   |
| sync     | 并发控制                              | 查询必加true,防缓存击穿        |
| allEntries| 清空所有key                          | 仅批量删除时用,避免误删        |
## 配置要点
| 缓存类型       | 配置核心                                                                 |
|----------------|--------------------------------------------------------------------------|
| 纯本地(Caffeine) | expireAfterWrite(60s) + maximumSize(10000)                              |
| Redis          | JSON序列化 + entryTtl(300s) + key前缀隔离                               |
| 混合缓存       | CompositeCacheManager,顺序:本地 → Redis → 数据库                       |

到此这篇关于SpringCache 缓存使用总结的文章就介绍到这了,更多相关SpringCache 缓存使用内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • SpringBoot整合kafka遇到的版本不对应问题及解决

    SpringBoot整合kafka遇到的版本不对应问题及解决

    这篇文章主要介绍了SpringBoot整合kafka遇到的版本不对应问题及解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-03-03
  • Java中的StopWatch计时利器使用指南

    Java中的StopWatch计时利器使用指南

    StopWatch通常用于测量一段代码执行所花费的时间,它能够精确地记录开始时间、结束时间,并计算出这中间的时间差,下面给大家介绍Java中的StopWatch计时利器的深度解析与使用指南,感兴趣的朋友一起看看吧
    2025-05-05
  • Nacos点击导入配置按钮无反应nacos配置用户名密码实现方式

    Nacos点击导入配置按钮无反应nacos配置用户名密码实现方式

    这篇文章主要介绍了Nacos点击导入配置按钮无反应nacos配置用户名密码实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2026-05-05
  • 快速了解Maven

    快速了解Maven

    这篇文章主要介绍了快速了解Maven,具有一定借鉴价值,需要的朋友可以参考下。
    2017-12-12
  • Restful API中的错误处理方法

    Restful API中的错误处理方法

    这篇文章主要给大家介绍了关于Restful API中错误处理方法的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-08-08
  • Oracle JDBC连接BUG解决方案

    Oracle JDBC连接BUG解决方案

    这篇文章主要介绍了Oracle JDBC连接BUG解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-10-10
  • MyBatis-Plus插件机制及通用Service新功能

    MyBatis-Plus插件机制及通用Service新功能

    这篇文章主要介绍了MyBatis-Plus插件机制以及通用Service、新功能,本文通过实例图文相结合给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-07-07
  • Spring中的事件发布机制原理解析

    Spring中的事件发布机制原理解析

    这篇文章主要介绍了Spring中的事件发布机制原理解析,当我们关心spring容器什么时候刷新,或者想在spring容器刷新的时候做一些事情,监听关心的事件,主要就是在ApplicationListener中写对应的事件,需要的朋友可以参考下
    2023-11-11
  • 面试题:Java中如何停止线程的方法

    面试题:Java中如何停止线程的方法

    这篇文章主要介绍了Java中如何停止线程的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-09-09
  • SpringBoot+Netty实现简单聊天室的示例代码

    SpringBoot+Netty实现简单聊天室的示例代码

    这篇文章主要介绍了如何利用SpringBoot Netty实现简单聊天室,文中的示例代码讲解详细,对我们学习SpringBoot有一定帮助,感兴趣的同学可以了解一下
    2022-02-02

最新评论