0
点赞
收藏
分享

微信扫一扫

Spring Cache(3)

闲云困兽 2022-01-08 阅读 92

1.删除1个缓存

/**
 * 级联更新所有关联的数据
 * @CacheEvict  失效模式
 * @param category
 */
@CacheEvict(value = {"category"},key ="'getTopCategorys'" )
@Transactional
@Override
public void updateCascade(CategoryEntity category) {
    this.updateById(category);
    categoryBrandRelationService.updateCategory(category.getCatId(),category.getName());
}

删除缓存
在这里插入图片描述

2.删除多个缓存

@Cacheable(value = "category", key = "#root.methodName")
@Override
public Map<String, List<Catelog2Vo>> getCatalogJson() {
    System.out.println("查询了数据库");
    //将数据库的多次查询变为一次
    List<CategoryEntity> selectList = this.baseMapper.selectList(null);

    //1、查出所有分类
    //1、1)查出所有一级分类
    List<CategoryEntity> level1Categorys = getParent_cid(selectList, 0L);

    //封装数据
    Map<String, List<Catelog2Vo>> parentCid = level1Categorys.stream().collect(Collectors.toMap(k -> k.getCatId().toString(), v -> {
        //1、每一个的一级分类,查到这个一级分类的二级分类
        List<CategoryEntity> categoryEntities = getParent_cid(selectList, v.getCatId());

        //2、封装上面的结果
        List<Catelog2Vo> catelog2Vos = null;
        if (categoryEntities != null) {
            catelog2Vos = categoryEntities.stream().map(l2 -> {
                Catelog2Vo catelog2Vo = new Catelog2Vo(v.getCatId().toString(), null, l2.getCatId().toString(), l2.getName().toString());

                //1、找当前二级分类的三级分类封装成vo
                List<CategoryEntity> level3Catelog = getParent_cid(selectList, l2.getCatId());

                if (level3Catelog != null) {
                    List<Catelog2Vo.Category3Vo> category3Vos = level3Catelog.stream().map(l3 -> {
                        //2、封装成指定格式
                        Catelog2Vo.Category3Vo category3Vo = new Catelog2Vo.Category3Vo(l2.getCatId().toString(), l3.getCatId().toString(), l3.getName());

                        return category3Vo;
                    }).collect(Collectors.toList());
                    catelog2Vo.setCatalog3List(category3Vos);
                }

                return catelog2Vo;
            }).collect(Collectors.toList());
        }
        return catelog2Vos;
    }));

    return parentCid;
}

使用@Caching

 /**
 * 级联更新所有关联的数据
 * @CacheEvict  失效模式
 * @param category
  */
 @Caching(evict = {@CacheEvict(value = "category",key = "'getTopCategorys'"),
   @CacheEvict(value = "category",key = "'getCatalogJson'")   })              
//    @CacheEvict(value = {"category"},key ="'getTopCategorys'" )
 @Transactional
 @Override
 public void updateCascade(CategoryEntity category) {
     this.updateById(category);
     categoryBrandRelationService.updateCategory(category.getCatId(),category.getName());
 }

在这里插入图片描述
或者

 /**
 * 级联更新所有关联的数据
 * @CacheEvict  失效模式
 * allEntries = true  删除某个分区下的所有数据
 * @param category
   */
  @CacheEvict(value = "category",allEntries = true)       //删除某个分区下的所有数据
  @Transactional
  @Override
  public void updateCascade(CategoryEntity category) {
      this.updateById(category);
      categoryBrandRelationService.updateCategory(category.getCatId(),category.getName());
  }

3.spring cache的不足

  • 读模式
    缓存穿透:查询一个null数据。解决方案:缓存空数据
    配置文件中spring.cache.redis.cache-null-values=true
    缓存击穿:大量并发进来同时查询一个正好过期的数据。解决方案:加锁
    默认是无加锁的;使用sync = true来解决击穿问题
    缓存雪崩:大量的key同时过期。解决:加随机时间
    加上过期时间配置文件中spring.cache.redis.time-to-live=3600000
  • 写模式:(缓存与数据库一致)
    1)、读写加锁。
    2)、引入Canal,感知到MySQL的更新去更新Redis
    3)、读多写多,直接去数据库查询就行
  • 总结:
    常规数据(读多写少,即时性,一致性要求不高的数据,完全可以使用Spring-Cache):写模式(只要缓存的数据有过期时间就足够了)
    特殊数据:特殊设计
  • 原理:
    CacheManager(RedisCacheManager)->Cache(RedisCache)->Cache负责缓存的读写
 /**
   * 查询所有1级分类
   * @Cacheable代表当前方法的结果需要缓存,若缓存中有则方法不会调用,若缓存中没有会调用方法并将结果放入缓存
   * 缓存默认行为:
   * a.若缓存中有则方法不会被调用
   * b.key默认自动生成,缓存的名字::SimpleKey []   (自动生成的key值)
   * c.缓存的value值,默认使用jdk序列化机制,将序列化后的数据存到redis
   * d.默认ttl时间为-1
   *
   * 原理:
   *   CacheAutoConfiguration(selectImports方法)--->CacheConfigurations(MAPPINGS)
   *   --->RedisCacheConfiguration-->cacheManager方法--->RedisCacheManager初始化所有的缓存(determineConfiguration方法
   *   每个缓存决定使用什么配置) --->createConfiguration方法
   *
   *
   *Spring-Cache的不足之处:
   *  1)、读模式
   *      缓存穿透:查询一个null数据。解决方案:缓存空数据
   *           配置文件中spring.cache.redis.cache-null-values=true
   *      缓存击穿:大量并发进来同时查询一个正好过期的数据。解决方案:加锁
   *               默认是无加锁的;使用sync = true来解决击穿问题
   *      缓存雪崩:大量的key同时过期。解决:加随机时间
   *        加上过期时间配置文件中spring.cache.redis.time-to-live=3600000
   *  2)、写模式:(缓存与数据库一致)
   *      1)、读写加锁。
   *      2)、引入Canal,感知到MySQL的更新去更新Redis
   *      3)、读多写多,直接去数据库查询就行
   *
   *  总结:
   *      常规数据(读多写少,即时性,一致性要求不高的数据,完全可以使用Spring-Cache):写模式(只要缓存的数据有过期时间就足够了)
   *      特殊数据:特殊设计
   *  原理:
   *      CacheManager(RedisCacheManager)->Cache(RedisCache)->Cache负责缓存的读写
   * @return
   */
  @Cacheable(value = {"category"},key ="#root.method.name",sync = true )
  @Override
  public List<CategoryEntity> getTopCategorys() {
      System.out.println(".....getTopCategorys..........");
      long startTime = System.currentTimeMillis();
      List<CategoryEntity> categoryEntityList = this.baseMapper.selectList(
              new QueryWrapper<CategoryEntity>().eq("parent_cid", 0));
      System.out.println("消耗时间:" + (System.currentTimeMillis() - startTime));
      return categoryEntityList;
  }
举报

相关推荐

0 条评论