SpringCache
Spring 3.1 开始 官方文档:https://docs.spring.io/spring-framework/docs/5.1.18.RELEASE/spring-framework-reference/integration.html#cache
Cache & CacheManager
SpringCache整合,简化缓存开发
- 引入依赖 spring-boot-starter-cache、spring-boot-starter-data-redis
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-cache --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-cache</artifactId> </dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2.自动配置
CacheAutoConfiguration会导入 RedisCacheConfiguration
自动配好了缓存管理器RedismanagerCache
3.手动配置
spring.cache.type=redis
4.测试使用
@Cacheable : 触发将数据保存到缓存的操作
@CacheEvict : 触发将数据从缓存中删除的操作
@CachePut : 不影响方法执行,更新缓存
@Caching : 组合以上多个操作
@CacheConfig :在类级别共享缓存的相同配置
- 开启缓存功能@Enablecaching
- 方法上添加@Cacheable 如果缓存中有,方法不用调用。如果缓存中没有,会调用方法,最后将方法的结果放入缓存
【缓存的分区(按照业务类型分)】 @Cacheable("category")
3.默认行为:
- 如果缓存中有,方法不会调用
- key默认自动生成,缓存的名字::Simplekey[]{自动生成key值}
- 缓存的value值,默认使用jdk序列化机制,将序列化后的数据存到redis
- 默认ttl时间:-1
4.自定义行为
- 指定生成的缓存使用的key,key属性制定,接收一个Spel
- 指定缓存的存活时间,配置文件中修改
- 将数据保存为json模式
自定义配置
spring.cache.redis.time-to-live=300000 spring.cache.type=redis spring.cache.redis.key-prefix=CACHE_ spring.cache.redis.use-key-prefix=true #是否缓存空值,防止缓存穿透 spring.cache.redis.cache-null-values=true
@EnableConfigurationProperties(CacheProperties.class) @Configuration @EnableCaching public class MyCacheConfig { @Bean RedisCacheConfiguration redisCacheConfiguration(CacheProperties cacheProperties){ RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig(); //config = config.entryTtl(); config = config.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer())); 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使用
@Cacheable 触发缓存写 (value=catagory:缓存分区,key=缓存后缀)
@Cacheable(value = {"catagory"},key = "#root.method.name") @Override public List<CategoryEntity> getLevel1Categorys() { List<CategoryEntity> list = baseMapper.selectList(new QueryWrapper<CategoryEntity>().eq("parent_cid", 0)); return list; }
@CacheEvict 缓存删
/** * 级联更新所有关联操作 * @CacheEvict:失效模式 * 同时进行多种缓存操作 * @param category */ // @Caching(evict = { // @CacheEvict(value = "category",key = "'getLevel1Categorys'"), // @CacheEvict(value = "category",key = "'getCatalogJson'") // }) /** *指定某分区(category)下的所有数据,全部删除。 */ @CacheEvict(value = "category",allEntries = true) @Transactional @Override public void updateCascade(CategoryEntity category) {
Spring-cache不足
1、读模式
- 缓存穿透:查询一个null数据。解决:缓存空数据;
#是否缓存空值,防止缓存穿透 spring.cache.redis.cache-null-values=true
- 缓存击穿:大量并发进来同时查询一个正好过期的数据。(默认不加锁)解决:加锁 sync=true(加锁)
@Cacheable(value = {"catagory"},key = "#root.method.name",sync = true)
- 缓存雪崩:大量key同时过期(超大应用存在考虑)。解决:加随机时间。加上过期时间
2、写模式(缓存与数据库一致)
- 读写加锁
- 引入Cane了,感知到mysql的更新去更新数据库
- 读多写多,直接去数据库查询
3、原理
使用整合redis
CacheManager(RedisCacheManager) -> Cache(RedisCache)
总结:
常规数据(读多写少,及时性一致性要求不高的数据);完全可以使用Spring-Cache;写模式( 只要有过期时间即可)
特殊数据:特殊设计