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 配置冲突解决

  • 问题RedisTemplateCacheConfig 配置可能冲突
  • 建议 :在大多数场景下,使用 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. 监控缓存命中率:定期检查缓存效果
相关推荐
大傻^11 分钟前
Spring AI Alibaba RAG实战:基于向量存储的检索增强生成
java·人工智能·spring
大傻^14 分钟前
Spring AI Alibaba 快速入门:基于通义千问的AI应用开发环境搭建
java·人工智能·后端·spring·springai·springaialibaba
伯恩bourne19 分钟前
Google Guava:Java 核心工具库的卓越之选
java·开发语言·guava
小王不爱笑13232 分钟前
Spring 基础核心
java
心勤则明42 分钟前
用 Spring AI Alibaba 打造智能查询增强引擎
java·人工智能·spring
Arva .43 分钟前
Spring 的三级缓存,两级够吗
java·spring·缓存
爱喝一杯白开水1 小时前
Java 定时任务完全指南
java
毕设源码-郭学长1 小时前
【开题答辩全过程】以 高校自动排课系统的设计与实现为例,包含答辩的问题和答案
java
彭于晏Yan1 小时前
MQTT消息服务
spring boot·后端·中间件
indexsunny2 小时前
互联网大厂Java面试实战:从Spring Boot到微服务架构的深度解析
java·spring boot·spring cloud·kafka·prometheus·security·microservices