微服务实战——SpringCache 整合 Redis

SpringCache 整合 Redis

1.配置

复制代码
spring.cache.type=redis

@EnableCaching
@EnableFeignClients(basePackages = "com.cwh.gulimall.product.feign")
@EnableDiscoveryClient
@SpringBootApplication
public class GulimallProductApplication {

    public static void main(String[] args) {
        SpringApplication.run(GulimallProductApplication.class, args);
    }

}

2.使用

复制代码
// 需要指定放入哪个名字的缓存(分区)
@Cacheable({"category"})  // 代表当前方法的结果需要缓存,如果缓存中有,不用调用方法;如果缓存中没有,调用方法后将结果放入缓存
@Override
public List<CategoryEntity> getLevel1Categories() {
    return list(new QueryWrapper<CategoryEntity>().eq("parent_cid", 0));
}

3.@Cacheable细节设置

1.缓存到Redis中数据具有如下的特点:

  • 如果缓存中有,方法不会被调用;
  • key默认自动生成;形式为"缓存的名字::SimpleKey ";
  • 缓存的value值,默认使用jdk序列化机制,将序列化后的数据缓存到redis;
  • 默认ttl时间为-1,表示永不

2.然而这些并不能够满足我们的需要,我们希望:

  • 能够指定生成缓存所使用的key;
  • 指定缓存的数据的存活时间;
  • 将缓存的数据保存为json形式

针对于第一点,使用@Cacheable注解的时候,设置key属性,接受一个SpEL(Spring Expression Language):

复制代码
@Cacheable(value = {"category"},key = "'level1Categorys'")

针对于第二点,在配置文件中指定ttl:

复制代码
  cache:
    type: redis
    redis:
      time-to-live: 3600000

// 需要指定放入哪个名字的缓存(分区)
    @Cacheable(value = {"category"},key = "#root.method.name")  // 代表当前方法的结果需要缓存,如果缓存中有,不用调用方法;如果缓存中没有,调用方法后将结果放入缓存
    @Override
    public List<CategoryEntity> getLevel1Categories() {
        return list(new QueryWrapper<CategoryEntity>().eq("parent_cid", 0));
    }

    @Cacheable(value = {"category"},key = "#root.methodName")
    @Override
    public Map<String, List<Catelog2Vo>> getCatalogJson() {
        /**
         * 优化循环查库
         */
        List<CategoryEntity> list = this.list();
        // 1.查出所有1级分类
        List<CategoryEntity> level1List = getParentCid(list, 0L);

        // 2.封装数据
        Map<String, List<Catelog2Vo>> parentCid = level1List.stream().collect(Collectors.toMap(k -> k.getCatId().toString(), v -> {
            // 2.1.查到该一级分类的二级分类
            List<CategoryEntity> level2List = getParentCid(list, v.getCatId());
            List<Catelog2Vo> catelog2Vos = null;
            if (level2List != null) {
                catelog2Vos = level2List.stream().map(c2 -> {
                    Catelog2Vo catelog2Vo = new Catelog2Vo(v.getCatId().toString(), null, c2.getCatId().toString(), c2.getName());

                    // 2.2.查到该二级分类对应的三级分类,并封装为vo
                    List<Catelog2Vo.Catelog3Vo> catelog3List = getParentCid(list, c2.getCatId())
                            .stream()
                            .map(c3 -> new Catelog2Vo.Catelog3Vo(
                                    catelog2Vo.getId(),
                                    c3.getCatId().toString(),
                                    c3.getName())
                            ).collect(Collectors.toList());

                    catelog2Vo.setCatalog3List(catelog3List);
                    return catelog2Vo;
                }).collect(Collectors.toList());
            }

            return catelog2Vos;
        }));
        return parentCid;
    }

4.自定义缓存配置------如何将数据以JSON的形式缓存到Redis

  1. 这涉及到修改缓存管理器的设置,CacheAutoConfiguration导入了RedisCacheConfiguration,而RedisCacheConfiguration中自动配置了缓存管理器RedisCacheManager,而RedisCacheManager要初始化所有的缓存,每个缓存决定使用什么样的配置,如果RedisCacheConfiguration有就用已有的,没有就用默认配置。

  2. 想要修改缓存的配置,只需要给容器中放一个"redisCacheConfiguration"即可,这样就会应用到当前RedisCacheManager管理的所有缓存分区中。

    package com.cwh.gulimall.product.config;

    import org.springframework.boot.autoconfigure.cache.CacheProperties;
    import org.springframework.boot.context.properties.EnableConfigurationProperties;
    import org.springframework.cache.annotation.EnableCaching;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.data.redis.cache.RedisCacheConfiguration;
    import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
    import org.springframework.data.redis.serializer.RedisSerializationContext;
    import org.springframework.data.redis.serializer.StringRedisSerializer;

    @EnableConfigurationProperties(CacheProperties.class)
    @Configuration
    @EnableCaching
    public class MyCacheConfig {
    /**
    * 配置文件中的东西没有用到
    * 1、原来和配置文件绑定的配置类是这样的
    * @ConfigurationProperties(prefix="spring.cache")
    * public class CacheProperties
    * 2、让他生效
    * @EnableConfigurationProperties(CacheProperties.class)
    * @return
    */
    @Bean
    RedisCacheConfiguration redisCacheConfiguration(CacheProperties cacheProperties){

    复制代码
         RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
    
         config = config.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()));
         // 在Redis中放入自动配置类,设置JSON序列化机制
         config = config.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));
         // 将配置文件中的所有配置都生效
         CacheProperties.Redis redisProperties = cacheProperties.getRedis();
         // 设置配置文件中的各项配置,如过期时间
         if (redisProperties.getTimeToLive() != null) {
             config = config.entryTtl(redisProperties.getTimeToLive());
         }
         if (redisProperties.getKeyPrefix() != null) {
             config = config.prefixKeysWith(redisProperties.getKeyPrefix());
         }
         if (!redisProperties.isCacheNullValues()) {
             config = config.disableCachingNullValues();
         }
         if (!redisProperties.isUseKeyPrefix()) {
             config = config.disableKeyPrefix();
         }
         return config;
     }

    }

    spring.cache.type=redis

    #设置超时时间,默认是毫秒

    spring.cache.redis.time-to-live=3600000

    #设置Key的前缀,如果指定了前缀,则使用我们定义的前缀,否则使用缓存的名字作为前缀

    spring.cache.redis.key-prefix=CACHE_

    spring.cache.redis.use-key-prefix=true

    #是否缓存空值,防止缓存穿透

    spring.cache.redis.cache-null-values=true

5.@CacheEvict

复制代码
/**
     * 级联更新,保证冗余字段一致
     * @CacheEvict:失效模式
     * 1.同时进行多种缓存操作  @Caching
     * 2.指定删除某个分区下的所有数据 @CacheEvict(value = "category", allEntries = true)
     * 3.存储同一类型的数据,都可以指定同一分区(缓存默认前缀:分区名)
     * @param category
     */
//    @CachePut  双写模式
//    @CacheEvict(value = "category", allEntries = true)
@Caching(evict = {
    @CacheEvict(value = "category", key = "'getLevel1Categories'"),
    @CacheEvict(value = "category", key = "'getCatalogJson'")
})
@Transactional
@Override
public void updateCascade(CategoryEntity category) {
this.updateById(category);

if(!StringUtils.isEmpty(category.getName())){
    // 保证冗余数据一致
    categoryBrandRelationService.updateCategory(category.getCatId(), category.getName());
    // TODO 其他数据一致
}
}
相关推荐
哦虎!1 小时前
【JavaEE】网络初识
java
for_ever_love__1 小时前
MySQL ORDER BY 排序优化:从 Using filesort 到索引有序扫描(含双路 / 单路排序原理)
java·mysql·优化·存储·by·order·filesort
大鸡腿同学2 小时前
手心向上,手心向下
后端
我是人✓2 小时前
Java文件上传三方式对比:从传统到SpringBoot
java·开发语言
欣栀♡2 小时前
JVM 频繁 Full GC 先看日志括号里的 cause,jstat 的 FGC 在 JDK 8 上会骗人
java·jvm
CCblandy2 小时前
令牌桶在 0.9 倍负载超发 19%、固定窗口边界放行 20 个:四种限流算法同构实测
后端·python·算法·性能优化·架构
IT研究室3 小时前
最新计算机毕业设计选题推荐-基于spring boot的葡萄酒文化宣传网站-网站-文档指导-Java-springboot
java·spring boot·课程设计
慧都小项3 小时前
MyEclipse 中创建和测试 JAX-RS REST 接口:从项目配置到 REST Explorer
java·restful·myeclipse·jax-rs
Wang's Blog3 小时前
Java 项目实战: 交友项目 - 入门案例:编写 Dubbo 服务提供者
java·dubbo·交友
唠点键盘之外的3 小时前
27 存量系统接大模型:旁挂一个 AI 微服务,老架构一行不改
人工智能·微服务·架构