【Java】java | CacheManager | redisCacheManager | @Cacheable失效

本文介绍了如何在SpringBoot项目中同时使用Ehcache和Redis作为缓存,包括添加Redis缓存配置、@Cacheable注解的使用、不同场景下的缓存策略以及Redis存储结果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、说明

        1、查询增加缓存,使用@Cacheable注解

        2、项目中已经用到了ehcache,现在需求是两个都用

二、备份配置

1、redisConfig增加代码

@Bean("redisCacheManage")
    @Primary
    public CacheManager redisCacheManager(RedisConnectionFactory factory) {
        Map<String, RedisCacheConfiguration> configurationMap = MapUtil.newHashMap();
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofMinutes(60))
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(keySerializer()))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(valueSerializer()))
                .disableCachingNullValues();
        return RedisCacheManager.builder(factory)
                .initialCacheNames(configurationMap.keySet())
                .withInitialCacheConfigurations(configurationMap)
                .cacheDefaults(config)
                .build();
    }

    private RedisSerializer<String> keySerializer() {
        return new StringRedisSerializer();
    }

    private RedisSerializer<Object> valueSerializer() {
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer =
                new Jackson2JsonRedisSerializer<>(Object.class);
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);

        // 此项必须配置,否则如果序列化的对象里边还有对象,会报如下错误:
        //     java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to XXX
        objectMapper.activateDefaultTyping(
                objectMapper.getPolymorphicTypeValidator(),
                ObjectMapper.DefaultTyping.NON_FINAL,
                JsonTypeInfo.As.PROPERTY);
        // 旧版写法:
        // objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);

        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);

        return jackson2JsonRedisSerializer;
    }

2、直接使用

1)缓存

@Cacheable(key ="'method_' + #tenantId + '_' + #bo.toString()", unless = "#result == null", cacheManager = "redisCacheManage", cacheNames = "api")

说明1:cacheNames其实是个前缀,也可以理解成分组的概念;方便手动删除时,根据前缀删除

2)示例截图

3)redis存储结果截图

~~

3、@Cacheable失效

1)@Cacheable用于直接调用的方法,可以缓存;被调用的方法,不进行缓存

比如:

~~

<think>好的,我现在要解决用户关于Redis的@Cacheable缓存失效的问题。根据用户提供的引用资料和问题描述,我需要整理可能的原因和对应的解决方法。 首先,用户提到在Spring Boot中使用@Cacheable注解时,缓存没有生成。他们给出了一些代码示例,比如在同一个类内部调用带有@Cacheable注解的方法,导致缓存失效。这可能是因为AOP代理的问题,因为Spring的AOP是基于代理的,同一个类中的方法调用不会经过代理,所以注解不会生效。这一点在引用3中提到过,需要将缓存方法移到另一个类中,确保调用方和被调用方不在同一个类里。 其次,用户引用了缓存配置可能不正确的情况。比如没有正确配置缓存管理器,或者Redis的连接参数有误。这时候需要检查配置文件,确保Redis的主机、端口、密码等正确,并且缓存管理器被正确注入。引用1和引用2都提到了配置的问题,可能用户没有正确设置相关属性,或者缓存名称与配置不匹配。 另外,缓存键的生成也是一个可能的问题。如果key的生成策略不正确,可能导致缓存无法正确存储或读取。用户需要检查@Cacheable的key属性是否正确,是否使用了SpEL表达式来动态生成key,比如是否包含了方法参数。例如,用户代码中的key是"'stock/give'+#memberId",需要确认memberId是否正确传递,是否可能为null。 还有序列化问题。如果RedisTemplate或缓存管理器配置了不兼容的序列化方式,可能导致存储的数据无法正确反序列化。这时候需要检查是否配置了合适的序列化器,比如Jackson2JsonRedisSerializer,而不是默认的JdkSerializationRedisSerializer。 此外,方法的访问权限也可能影响AOP代理。如果缓存方法是私有的或者非public的,Spring的AOP可能无法代理这个方法,导致注解失效。需要确保缓存方法是public的。 用户还可能没有启用缓存功能。在Spring Boot主类上是否添加了@EnableCaching注解,这是启用缓存的前提条件,如果漏掉这个注解,所有缓存相关的注解都不会生效。 最后,其他因素比如缓存的条件设置,比如unless、condition属性可能排除了某些情况,或者缓存的有效期设置过短,导致数据被立即清除。需要检查这些属性是否正确配置。 总结下来,可能的原因包括:同类内部调用、缓存配置错误、缓存键不正确、序列化问题、方法访问权限、未启用缓存以及其他条件限制。解决方法对应每个原因,比如拆分类、检查配置、调整key、配置序列化、确保方法公开、添加启用注解等。 接下来需要将这些原因和解决方法组织成用户容易理解的步骤,用中文清晰表达,并确保LaTeX格式正确,行内公式用$...$,独立公式用$$...$$。同时生成相关问题,帮助用户进一步排查问题。</think>### Redis @Cacheable 缓存失效原因及解决方法 #### 一、同类内部调用导致失效(最常见原因) 当在**同一个类**中调用带有 `@Cacheable` 注解的方法时,由于Spring AOP代理机制的限制,注解不会生效[^3]。 **示例代码问题**: ```java public void get() { stockGive(0L); // 同类内部调用,缓存失效 } @Override @Cacheable(value = "common", key = "'stock/give'+#memberId") public List<Map<String, Object>> stockGive(Long memberId) { // 业务逻辑 } ``` **解决方法**: 1. 将缓存方法定义在独立的接口和实现类中[^3]。 2. 通过注入自身代理对象调用(需启用 `@EnableAspectJAutoProxy(exposeProxy = true)`): ```java public void get() { ((YourService) AopContext.currentProxy()).stockGive(0L); } ``` --- #### 二、缓存配置错误 1. **未启用缓存功能**: 确保主类添加 `@EnableCaching` 注解。 2. **Redis配置错误**: 检查 `application.yml` 中的连接参数: ```yaml spring: redis: host: 127.0.0.1 port: 6379 password: 123456 ``` 3. **缓存管理器未注入**: 确认配置类中声明了 `RedisCacheManager`,例如: ```java @Bean public RedisCacheManager cacheManager(RedisConnectionFactory factory) { return RedisCacheManager.create(factory); } ``` --- #### 三、缓存键(Key)生成问题 1. **Key表达式错误**: 使用SpEL表达式时需确保语法正确,例如 `key = "'stock/give'+#memberId"`。 2. **参数为null或未传递**: 若 `memberId` 为 `null`,会导致Key生成失败。需添加空值校验: ```java @Cacheable(value = "common", key = "'stock/give'+#memberId", unless = "#memberId == null") ``` --- #### 四、序列化不兼容 默认序列化方式(JDK序列化)可能导致数据无法识别。 **解决方法**: 在配置类中指定JSON序列化器: ```java @Bean public RedisCacheConfiguration redisCacheConfiguration() { return RedisCacheConfiguration.defaultCacheConfig() .serializeValuesWith(RedisSerializationContext.SerializationPair .fromSerializer(new GenericJackson2JsonRedisSerializer())); } ``` --- #### 五、其他常见原因 | 原因 | 解决方法 | |---------------------|--------------------------------------------------------------------------| | 方法非public | 确保缓存方法是 `public` | | 条件过滤(unless) | 检查 `unless` 或 `condition` 是否误过滤了缓存写入[^1] | | 缓存过期时间过短 | 调整 `spring.cache.redis.time-to-live` 配置 | --- #### 六、验证缓存是否生效 1. 使用 `redis-cli` 查看键是否存在: ```bash KEYS "common::stock/give0" ``` 2. 在方法内添加日志,确认是否重复执行。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值