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;
}