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. 监控缓存命中率:定期检查缓存效果
相关推荐
Hx_Ma166 小时前
SpringMVC框架提供的转发和重定向
java·开发语言·servlet
期待のcode7 小时前
原子操作类LongAdder
java·开发语言
舟舟亢亢8 小时前
Java集合笔记总结
java·笔记
小酒窝.8 小时前
【多线程】多线程打印ABC
java
乡野码圣8 小时前
【RK3588 Android12】RCU机制
java·jvm·数据库
JAVA+C语言8 小时前
如何优化 Java 多主机通信的性能?
java·开发语言·php
编程彩机9 小时前
互联网大厂Java面试:从分布式架构到大数据场景解析
java·大数据·微服务·spark·kafka·分布式事务·分布式架构
xxxmine10 小时前
redis学习
数据库·redis·学习
小酒窝.10 小时前
【多线程】多线程打印1~100
java·多线程
君爱学习10 小时前
基于SpringBoot的选课调查系统
java