SpringCache 缓存抽象Cache Abstraction
1、简介
- spring从3.1开始定义了org.springframework.cache.Cache和org.springframework.cache.CacheManger接口来统一不同的缓存技术;并支持使用JCache(JSR-107)注解简化我们开发
- Cache接口为缓存定义的组件规范定义,包含缓存的各种操作集合 Cache接口下spring提供了各种xxCache的实现,如RedisCache,EhCacheCache,ConcurrentMapCache等
- 每次调用需要缓存功能的方法时,spring都会检查检查指定参数的指定目标是否已经被调用过;如果有就直接从缓存中获取方法调用后的结果,如果没有就调用方法并缓存结果后返回给用户。下次调用直接从缓存中获取。
- 使用spring缓存抽象时我们需要关注以下两点
- 1、确定方法需要被缓存以及他们的缓存策略
- 2、从缓存中读取之前缓存储存的数据
2、基础概念
给应用配一个或多个缓存管理器CacheManager(ConcurrentHashMap)
两个接口=》两个功能
第一个功能按照名字得到一个缓存
Cache缓存名字 当前缓存名字
如何从缓存里面查询一个数据
如何从缓存中保存一个数据 按照key value保存一个数据
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-y3D4XKO9-1651054143745)(C:\Users\靓仔在此\AppData\Roaming\Typora\typora-user-images\image-20220427133854151.png)]
从缓存中按照key移除一个数据
清空整个缓存
第二个功能相当于获取缓存管理器中所有缓存
CacheManager(ConcurrentHashMap)
store存储数据文件
3整合SpringCache
缓存的自动配置CacheAutoConfiguration
缓存中xml所有能配的属性都在CacheProperties.class中
缓存选择器
CacheConfigurations.getConfigurationClass(type[i])
按照缓存类型进行映射
CacheAutoConfiguration会导入RedisCacheConfiguration RedisCacheConfiguration 自动加载缓存管理器
缓存管理器会根据所有配置的缓存名字
会在RedisCacheConfiguration 进行初始化
初始化缓存做的事情非常多 拿到每一个缓存开始遍历,把缓存配置跟当前缓存名放在一起,配置都是默认配置 再利用默认配置再初始化所有的缓存
把初始化的缓存数据往initialCaches里一放
缓存规则
开始整合
1,引入依赖
2,指定缓存类型
3,开启缓存,以及通过注解@Cacheable完成缓存操作
/**
*
* //1,每一个需要缓存的数据我们都来指定要放到哪个名字的缓存【缓存的分区(按照业务类型分)】
* //2, @Cacheable("{category}")
* 代表当前方法的结果需要缓存
* 如果缓存中有,方法不需要调用
* 如果缓存中没有 会调用方法 最后将方法的结果放入缓存
* //3默认行为
* 1如果缓存中有,方法不调用
* 2key默认自动生成 缓存名字:SimpleKey{}(自主生成key值)
* 3缓存的value的值,默认使用jdk序列化机制,将序列化后的数据存到redis
* 4默认时间ttl:-1 永不过期
*
* 自定义操作
* 1,指定生成的缓存使用的key key属性指定,接受一个SpEl
* SpEl的详细查看官网
* 2,指定缓存的数据的存活时间 配置文件中修改了ttl
* 3,将数据保存为json数据
*
*
* @return
*/
@Cacheable(value = {"category"},key ="#root.method.name") //通过#root.method.name的方法名字
@Override
public List<CategoryEntity> getLevel1Categorys() {
List<CategoryEntity> categoryEntities = baseMapper.selectList(new QueryWrapper<CategoryEntity>().eq("parent_cid", 0));
return categoryEntities;
//系统的一致性解决方案:
//1缓存的所有数据都有过期时间,数据过期下一次查询触发主动更新
//2读写数据的时候,加上分布式的读写锁。
// 经常写,经常读
//同时修改缓存中数据
//redis.del("catelogJSON"); 等待下次主动查询进行更新
}
* 自定义缓存配置MyCacheConfig
4)原理:
* CacheAutoConfiguration->RedisCacheConfiguration
* ->自动配置了RedisCacheManager
* ->初始化所有的缓存
* ->每个缓存决定使用什么配置
* ->如果redisCacheConfiguration有就用已有的,没有就用默认配置
* ->想改缓存的配置,只需要给容器中放一个RedisCacheConfiguration即可
* ->就会应用到当前RedisCacheManager管理的所有缓存配置中
*
@EnableConfigurationProperties(CacheProperties.class)//加载配置文件,使配置文件生效
@EnableCaching//开启注解
@Configuration
public class MyCacheConfig {
// @Resource
// CacheProperties cacheProperties;
/**
* 配置文件中的东西没有用上;
*
* 1,原来和配置文件绑定的配置类是这样的
* @ConfigurationProperties(prefix="spring.cache")
* public class CacheProperties
*
* 2,要让他生效
* @EnableConfigurationProperties(CacheProperties.class)
* @return
*/
@Bean
RedisCacheConfiguration redisCacheConfiguration(CacheProperties cacheProperties){
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
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.type=redis
#spring.cache.cache-names=qq, 毫秒为单位
spring.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
- 缓存失效模式
- 批量删除
- 删除分区下所有数据
双写模式
@CachePut
rue
- 缓存失效模式
- 批量删除
- 删除分区下所有数据
双写模式
@CachePut