(5)@CacheEvict注解

(a)修改 application.properties 文件,使用分区的前缀

spring.cache.type=redisspring.cache.redis.time-to-live=3600000#如果指定了前缀就用我们指定的前缀,如果没有就默认使用缓存的名字作为前缀#spring.cache.redis.key-prefix=CACHE_spring.cache.redis.use-key-prefix=true#是否缓存空值 防止缓存穿透spring.cache.redis.cache-null-values=true (b)修改 com.atguigu.gulimall.product.service.impl.CategoryServiceImpl 的 updateCascade 方法

/** * 级联更新所有关联的数据 * @CacheEvict:失效模式 * @param category */ @CacheEvict(value = "category", key = "'getLevel1Catagories'") //category:key @Override @Transactional public void updateCascade(CategoryEntity category) { this.updateById(category); categoryBrandRelationService.updateCategory(category.getCatId(), category.getName()); //同时修改缓存中的数据 //redis.del("catalogJson");等待下次主动查询进行更新 } 测试: 访问 http://localhost:10000,redis中结果如下:

启动网关、启动renren-fast,修改分类,redis中结果:

思考:如果修改分类要清除多个缓存呢,例如修改分类,需要删除一级、二级和三级缓存

(c)先来修改之前的 getCatalogJson 方法,获取分类的json数据,使用@Cacheable注解缓存数据

@Cacheable(value = "category", key = "#root.methodName")@Overridepublic Map> getCatalogJson(){ System.out.println("查询了数据库....."); List selectList = baseMapper.selectList(null); List level1Catagorys = getParent_cid(selectList, 0L); //2、封装数据 Map> parent_cid = level1Catagorys.stream().collect(Collectors.toMap(k -> k.getCatId().toString(), v -> { // 1、每一个的一级分类,查到这个以及分类的二级分类 List categoryEntities = getParent_cid(selectList, v.getCatId()); //2、封装上面的结果 List catelog2Vos = null; if (categoryEntities != null) { catelog2Vos = categoryEntities.stream().map(l2 -> { Catelog2Vo catelog2Vo = new Catelog2Vo(v.getCatId().toString(), null, l2.getCatId().toString(), l2.getName()); //1、找当前二级分类的三级分类封装成vo List level3Catalog = getParent_cid(selectList, l2.getCatId()); if(level3Catalog!=null){ List collect = level3Catalog.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(collect); } return catelog2Vo; }).collect(Collectors.toList()); } return catelog2Vos; })); return parent_cid;} 清空redis,启动网关,多次访问gulimall.com。查看一级菜单和json数据是否都只访问了一次数据库

可以看到,多次访问后,一级分类菜单和分类的json数据都只访问了一次数据库,查看redis情况

可以看到,redis中有两个key,一个是一级分类,一个是分类的json数据,并且key的前缀都是 “category”,后缀是方法名

思考:现在我们从管理后台修改分类,如何一次性是这两个key都失效呢

(d)修改 com.atguigu.gulimall.product.service.impl.CategoryServiceImpl 的 updateCascade 方法

使用 @Caching 注解,里面存储数组对象,指定多个删除的key值

/** * 级联更新所有关联的数据 * @CacheEvict:失效模式 * 1、同时进行多种缓存操作 @Caching * @param category *///@CacheEvict(value = "category", key = "'getLevel1Catagories'")@Caching(evict = { @CacheEvict(value = "category", key = "'getLevel1Catagories'"), @CacheEvict(value = "category", key = "'getCatalogJson'")})//category:key@Override@Transactionalpublic void updateCascade(CategoryEntity category) { this.updateById(category); categoryBrandRelationService.updateCategory(category.getCatId(), category.getName()); //同时修改缓存中的数据 //redis.del("catalogJson");等待下次主动查询进行更新} 测试: 访问 gulimall.com,然后后台修改分类,发现两个key都被删除了,这里就不再截图展示了 思考:这样一个一个指定过于麻烦,我们如何一次性操作简便呢(e)修改 com.atguigu.gulimall.product.service.impl.CategoryServiceImpl 的 updateCascade 方法

使用 @CacheEvict(value = "category", allEntries = true),直接一次性删除分区 “category”里面的数据

/** * 级联更新所有关联的数据 * @CacheEvict:失效模式 * 1、同时进行多种缓存操作 @Caching * 2、指定删除某个分区下的所有数据 @CacheEvict(value = "category", allEntries = true) * 3、存储同一类型的数据,都可以指定成同一个分区。分区名默认就是缓存的前缀 * @param category */ //@CacheEvict(value = "category", key = "'getLevel1Catagories'")// @Caching(evict = {// @CacheEvict(value = "category", key = "'getLevel1Catagories'"),// @CacheEvict(value = "category", key = "'getCatalogJson'")// }) //category:key @CacheEvict(value = "category", allEntries = true) @Override @Transactional public void updateCascade(CategoryEntity category) { this.updateById(category); categoryBrandRelationService.updateCategory(category.getCatId(), category.getName()); //同时修改缓存中的数据 //redis.del("catalogJson");等待下次主动查询进行更新 }