一、整合SpringCache
1、导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
2.配置
spring:
cache:
type: redis
3.开启测试及注解
1.开启缓存
2.添加注解
简单实例
//每一个需要缓存的数据我们都来指定放在那个名字的缓存
@Cacheable("category") //代表当前方法结果需要缓存,如果缓存中有,方法不调用。如果方法没有缓存调用
@Override
public List<CategoryEntity> getLevel1Categories() {
List<CategoryEntity> categoryEntityList = this.list(new QueryWrapper<CategoryEntity>().eq("cat_level", 1));
return categoryEntityList;
}
注意@Cacheable为org.springframework.cache.annotation.Cacheable
不是springfox.documentation.annotations.Cacheable
3.默认行为
- 如果缓存中有,方法不用调用
- key默认自动生成:缓存的名字::SimpleKey []
- 缓存默认的值默认用jdk序列化,讲序列化后的值存入redis
- 默认ttl时间-1
4.自定义
-
指定生成缓存使用的key
@Cacheable(value = {"category"}, key = "'level1'")
-
指定缓存的数据的存活时间
spring: cache: type: redis redis: time-to-live: 36000000
3.将数据保存为json形式
@EnableConfigurationProperties(CacheProperties.class)//自动注入配置类,可不用@Autowire,在形参中直接写即可
@EnableCaching
@Configuration
public class MyCacheConfig {
@Bean
public RedisCacheConfiguration redisCacheConfiguration(CacheProperties cacheProperties){
//获取默认配置类
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
//配置key编码格式
config = config.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(RedisSerializer.string()));
//配置value编码格式
config = config.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(RedisSerializer.json()));
//添加配置内后,会覆盖yaml中配置的一些属性,如此处的过期时间,故要重新获取
config = config.entryTtl(cacheProperties.getRedis().getTimeToLive());
return config;
}
}
三、失效模式
- 注解 @CacheEvict(value = “category”, allEntries = true)
方法一
@Transactional
@CacheEvict(value = "category", allEntries = true)
@Override
public void updateDetail(CategoryEntity category) {
this.updateById(category);
Long catId = category.getCatId();
String categoryName = category.getName();
if (categoryName != null && categoryName != "")
categoryBrandRelationService.updateDeatil(catId,categoryName);
}
方法二
@Caching(evict = {
@CacheEvict(value = {"category"}, key = "'level1'"),
@CacheEvict(value = {"category"}, key = "'getCatalogJson'")
})
public void updateDetail(CategoryEntity category) {
this.updateById(category);
Long catId = category.getCatId();
String categoryName = category.getName();
if (categoryName != null && categoryName != "")
categoryBrandRelationService.updateDeatil(catId,categoryName);
}
四、Spring-Cache的不足
-
读模式
-
缓存穿透:查询一个null数据 解决无需考虑 空数据可写入缓存
-
缓存击穿:大量并发查询一个正好过期的数据 解决:加锁sync = true
@Cacheable(value = {"category"}, key = "'level1'", sync = true)
-
缓存雪崩:大量key同时过期。加上随机时间。加上过期时间
-
-
写模式
- 读写加锁
- 引入Canal,感知到Mysql的更新去更新数据库
- 读多写多,直接去数据库查询就行
y = “‘level1’”, sync = true)
```
- 缓存雪崩:大量key同时过期。加上随机时间。加上过期时间
-
写模式
- 读写加锁
- 引入Canal,感知到Mysql的更新去更新数据库
- 读多写多,直接去数据库查询就行
常规数据(读多写少,及时性,一致性要求不高的数据):完全可以使用Spring-Cache:写模式(只要缓存的数据有过期)