SpringBoot--Spring Boot原生缓存基于Redis的Cacheable注解使用

SpringBoot--Spring Boot原生缓存基于Redis的Cacheable注解使用

文章目录

  • [SpringBoot--Spring Boot原生缓存基于Redis的Cacheable注解使用](#SpringBoot--Spring Boot原生缓存基于Redis的Cacheable注解使用)
    • 概述
    • [1. 基础配置](#1. 基础配置)
      • [1.1 添加依赖](#1.1 添加依赖)
      • [1.2 配置文件](#1.2 配置文件)
      • [1.3 序列化配置](#1.3 序列化配置)
    • [2. 缓存注解使用](#2. 缓存注解使用)
      • [2.1 @Cacheable - 缓存查询](#2.1 @Cacheable - 缓存查询)
      • [2.2 @CacheEvict - 缓存清除](#2.2 @CacheEvict - 缓存清除)
    • [3. 自定义TTL管理](#3. 自定义TTL管理)
      • [3.1 自定义缓存管理器](#3.1 自定义缓存管理器)
      • [3.2 缓存配置类](#3.2 缓存配置类)
      • [3.3 不同TTL的缓存使用](#3.3 不同TTL的缓存使用)
    • [4. 关键注意事项](#4. 关键注意事项)
      • [4.1 配置冲突解决](#4.1 配置冲突解决)
      • [4.2 缓存键生成规则](#4.2 缓存键生成规则)
      • [4.3 TTL优先级](#4.3 TTL优先级)
      • [4.4 空值缓存策略](#4.4 空值缓存策略)
      • [4.5 最佳实践](#4.5 最佳实践)

概述

Spring Boot 通过 @Cacheable 和 @CacheEvict 注解简化了 Redis 缓存的使用,提供了声明式的缓存管理方案。

1. 基础配置

1.1 添加依赖

xml 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

1.2 配置文件

yml 复制代码
spring:
  redis:
    host: 127.0.0.1
    port: 6379
    password: 123456
    database: 1
  cache:
    type: redis
    redis:
      cache-null-values: false   # 不缓存null值
      time-to-live: 9000ms      # 默认过期时间
      use-key-prefix: true      # 使用key前缀

1.3 序列化配置

java 复制代码
@Configuration
public class RedisConfig {
    
    @Bean
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<Object, 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);
        
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(serializer);
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setHashValueSerializer(serializer);
        
        return template;
    }
}

2. 缓存注解使用

2.1 @Cacheable - 缓存查询

  • 参数说明

    • value ="bills":缓存名称,在 Redis 中作为前缀

    • key ="#id":缓存键,使用方法的 id 参数

java 复制代码
@Service
public class BillService {
    
    /**
     * 查询账单并缓存结果
     * value: 缓存名称(Redis中的前缀)
     * key: 缓存键,使用SpEL表达式
     */
    @Cacheable(value = "bills", key = "#id")
    public ResultJSON findBillById(Integer id) {
        // 只有缓存不存在时才会执行此方法
        return ResultJSON.ok(this.getById(id));
    }
}
  • 工作机制:
  1. 检查缓存中是否存在键为 bills::[id] 的数据
  2. 存在:直接返回缓存数据,不执行方法
  3. 不存在:执行方法,将结果存入缓存

2.2 @CacheEvict - 缓存清除

  • 参数说明

    • value ="bills":缓存名称,与 @Cacheable 中的一致

    • key ="#id":缓存键,使用方法的 id 参数

java 复制代码
@CacheEvict(value = "bills", key = "#id")
public ResultJSON deleteBill(Integer id) {
    // 方法执行成功后,自动删除对应的缓存
    return ResultJSON.ok(this.removeById(id));
}
清除所有缓存
java 复制代码
@CacheEvict(value = "bills", allEntries = true)
public ResultJSON clearAllBills() {
    // 清除bills缓存区域的所有数据
    return ResultJSON.ok("所有账单缓存已清除");
}

3. 自定义TTL管理

3.1 自定义缓存管理器

java 复制代码
public class MyRedisCacheManager extends RedisCacheManager {
    
    public MyRedisCacheManager(RedisCacheWriter cacheWriter, 
                              RedisCacheConfiguration defaultCacheConfiguration) {
        super(cacheWriter, defaultCacheConfiguration);
    }
    
    @Override
    protected RedisCache createRedisCache(String name, RedisCacheConfiguration cacheConfig) {
        // 解析缓存名称中的TTL配置,格式:cacheName#ttlSeconds
        String[] array = StringUtils.delimitedListToStringArray(name, "#");
        name = array[0];
        
        if (array.length > 1) {
            long ttl = Long.parseLong(array[1]);
            cacheConfig = cacheConfig.entryTtl(Duration.ofSeconds(ttl));
        }
        
        return super.createRedisCache(name, cacheConfig);
    }
}

3.2 缓存配置类

java 复制代码
@Configuration
public class CacheConfig extends CachingConfigurerSupport {
    
    @Value("${spring.redis.host}")
    private String hostName;
    @Value("${spring.redis.password}")
    private String password;
    @Value("${spring.redis.port}")
    private Integer port;
    @Value("${spring.redis.database}")
    private int database;
    
    @Bean
    public CacheManager cacheManager() {
        // 默认缓存配置(1天过期)
        RedisCacheConfiguration defaultCacheConfig = RedisCacheConfiguration
            .defaultCacheConfig()
            .entryTtl(Duration.ofDays(1))
            .computePrefixWith(cacheName -> "caching:" + cacheName);
        
        return new MyRedisCacheManager(
            RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory()),
            defaultCacheConfig
        );
    }
    
    @Bean
    public RedisConnectionFactory redisConnectionFactory() {
        RedisStandaloneConfiguration config = new RedisStandaloneConfiguration();
        config.setHostName(hostName);
        config.setPort(port);
        config.setDatabase(database);
        config.setPassword(RedisPassword.of(password));
        //        configuration.setHostName("127.0.0.1");
        //        configuration.setPort(6379);
        //        configuration.setDatabase(0);
        //        configuration.setPassword("123456"); // 密码
        
        return new LettuceConnectionFactory(config);
    }
}

3.3 不同TTL的缓存使用

java 复制代码
@Service
public class BillService {
    
    // 3600秒过期
    @Cacheable(cacheNames = "billCache#3600", key = "#id")
    public ResultJSON findBillById(Integer id) {
        return ResultJSON.ok(this.getById(id));
    }
    
    // 4800秒过期  
    @Cacheable(cacheNames = "providerCache#4800", key = "#id")
    public ResultJSON getProviderById(Integer id) {
        return ResultJSON.ok(this.getById(id));
    }
    
    // 清除指定缓存(需要匹配TTL配置)
    @CacheEvict(cacheNames = "billCache#3600", key = "#id")
    public ResultJSON deleteBill(Integer id) {
        return ResultJSON.ok(this.removeById(id));
    }
}

4. 关键注意事项

4.1 配置冲突解决

  • 问题 :RedisTemplate 与 CacheConfig 配置可能冲突
  • 建议 :在大多数场景下,使用 CacheConfig 统一管理缓存配置

4.2 缓存键生成规则

  • 默认格式 :caching::cacheName::key
  • 示例 :caching:billCache::1

4.3 TTL优先级

  1. 最高 :注解中通过 # 指定的TTL(如 billCache#3600)
  2. 中等:YAML中针对具体cacheName的配置
  3. 最低:全局默认TTL配置

4.4 空值缓存策略

yml 复制代码
spring:
  cache:
    redis:
      cache-null-values: false  # 推荐设置为false,避免缓存空值

4.5 最佳实践

  1. 合理设置TTL:根据数据更新频率设置不同的过期时间
  2. 避免缓存雪崩:为不同缓存设置不同的TTL
  3. 及时清理缓存:数据更新后立即清除相关缓存
  4. 监控缓存命中率:定期检查缓存效果
相关推荐
时间的拾荒人9 分钟前
Redis 哨兵(Sentinel)详解:原理、选举机制与实战部署
redis·面试·架构·sentinel
黄连木笛10 分钟前
Redis Insight 汉化教程:Windows / macOS / Linux 设置中文界面(附繁體、教程汉化、关闭自动更新)
数据库·redis·缓存
30955666612 分钟前
股票接口返回 404 与空数组的排查笔记:证书状态与级别参数
java·笔记·python·ios·iphone·股票数据api·股票数据接口
nice_lcj52015 分钟前
MySQL 存储引擎入门:InnoDB 和 MyISAM 到底怎么选
java·数据库·mysql·面试·innodb·存储引擎·myisam
文丑颜不良啊31 分钟前
LeetCode2861~2880题目解析
java·leetcode
装不满的克莱因瓶42 分钟前
设计模式之策略模式核心概念和应用场景
java·后端·设计模式·架构·系统架构·策略模式
晴天的雨.9921 小时前
【C++】继承篇
java·开发语言·c++
SomeOtherTime1 小时前
第 1 讲:内存布局与所有权解剖——栈帧、胖指针与“移动/拷贝”在汇编层面的真实面目
java·开发语言·汇编
qq_406981031 小时前
c++ lamda(三)Lambda表达式
java·前端·c++
头发还在的女程序员1 小时前
Java在线租房系统源码解析:Spring Boot+Vue 3+UniApp房源管理与预约看房方案
java·vue.js·spring boot·租房小程序·租房系统·租房软件