springboot集成redis使用@Cacheable存入值,但redisTemplate取值时始终为null

项目场景:

springboot2.x集成了redis时,使用@Cacheable注解进行缓存,同时自定义了一个RedisUtils(使用到了自定义的RedisTemplate)方便获取缓存值


问题描述:

单独使用缓存注解时可以正常存取值,单独使用RedisUtils也可以正常存取值,但通过注解存值,RedisUtils获取值时始终为null


原因分析:

有两点原因:

  1. RedisUtils中的RedisTemplate并不是配置时注入的bean(因为SpringBoot中也提供了RedisTemplate),这样可能会造成拿不到值的情况(不常见)
  2. RedisTemplate和RedisCacheManager序列化方式不一样,这个问题需要明确@Cacheable和RedisTemplate调用的方式(下面有提到),在配置中如果两个类序列化的方式不一样,那么混用时也就拿不到数据
  • @Cacheable是spring cache提供的,实现方式也是通过CacheManager进行缓存的读写
  • RedisTemplate则是springboot提供的一个关于读写redis数据的类

解决方案:

针对第一个原因,可以在自定义RedisTemplate时添加一个@Primary注解,这样就相当于告诉spring容器,如果容器中有多个RedisTemplate,这个自定义的RedisTemplate需要优先被取出,例如:

@Bean
@Primary
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
    RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
    redisTemplate.setConnectionFactory(factory);

    // 使用GenericToStringSerializer来序列化和反序列化redis的key
    GenericToStringSerializer<String> stringGenericToStringSerializer = new GenericToStringSerializer<>(String.class);
    redisTemplate.setKeySerializer(stringGenericToStringSerializer);
    redisTemplate.setHashKeySerializer(stringGenericToStringSerializer);
    redisTemplate.setStringSerializer(stringGenericToStringSerializer);

    // 使用FastJsonRedisSerializer来序列化和反序列化redis的值
    FastJsonRedisSerializer<Object> fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class);
    redisTemplate.setValueSerializer(fastJsonRedisSerializer);
    redisTemplate.setHashValueSerializer(fastJsonRedisSerializer);

    return redisTemplate;
}

针对第二点原因,只要保证RedisTemplate和CacheManager序列化方式一样即可,最保险的写法如下:

@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
    /**
     * redisTemplate相关
     */
    @Bean("customRedisTemplate")
    @Primary
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(factory);

        // 使用GenericToStringSerializer来序列化和反序列化redis的key
        GenericToStringSerializer<String> stringGenericToStringSerializer = new GenericToStringSerializer<>(String.class);
        redisTemplate.setKeySerializer(stringGenericToStringSerializer);
        redisTemplate.setHashKeySerializer(stringGenericToStringSerializer);
        redisTemplate.setStringSerializer(stringGenericToStringSerializer);

        // 使用FastJsonRedisSerializer来序列化和反序列化redis的值
        FastJsonRedisSerializer<Object> fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class);
        redisTemplate.setValueSerializer(fastJsonRedisSerializer);
        redisTemplate.setHashValueSerializer(fastJsonRedisSerializer);

        return redisTemplate;
    }

    /**
     * 选择redis作为默认缓存工具
     */
    @Bean("redisCacheManager")
    @Primary
    @DependsOn("customRedisTemplate")
    public CacheManager cacheManager(RedisTemplate<String, Object> redisTemplate) {
        return RedisCacheManager.RedisCacheManagerBuilder
                .fromConnectionFactory(redisTemplate.getConnectionFactory())
                // 设置缓存默认永不过期
                .cacheDefaults(
                        RedisCacheConfiguration.defaultCacheConfig()
                                // 不缓存null(需要与unless = "#result == null"共同使用)
                                .disableCachingNullValues()
                                .serializeKeysWith(
                                        RedisSerializationContext.SerializationPair.fromSerializer(redisTemplate.getStringSerializer()))
                                .serializeValuesWith(
                                        RedisSerializationContext.SerializationPair.fromSerializer(redisTemplate.getValueSerializer())))
                // 配置同步修改或删除 put/evict
                .transactionAware()
                .build();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值