Spring cache
基础概念
有CacheManager来管理缓存 缓存管理器中根据不同的业务来将不同的缓存进行分区
源码
可以查看CacheAutoConfiguration来查看spring cache自动配置了哪些东西
CacheProperties.class类中保存spring cache在yaml或properties中配置项
这里将不同的缓存类型添加到配置中
缓存类型如: redis 内存等
cacheType类如下
进入cacheConfiguration中 有块static语句块 根据不同
这里根据传入的缓存类型的不同 进行赋值
这里自动配置已经将缓存管理器创建好了
配置
首先导入pom包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
将cache类型设置为redis
spring:
cache:
type: redis
添加@EnableCaching
注解
@Cacheable
将该注解放入可缓存的业务方法 如: 查询商品分类的service方法中 若缓存中无数据则调用此方法并保存至redis中 若缓存中有数据则该方法不会被调用
默认缓存名称: cacacheName::SimpleKey []
默认缓存时间: 永久
默认存储类型: java反序列化
属性
value: 接受一个string类型的数组对象 缓存名称
key: 自定义缓存key名称 使用的是SpEL表达式 spring文档中有些
自定义缓存配置
首先查看源码进入到CacheAutoConfiguration
自动配置
配置中有个方法 这个方法是根据传入的缓存类型将缓存类型添加到配置中 我们跳转掉CacheConfigurations中
可以看到可支持的配置 我们使用的是redis 我们进入到RedisCacheConfiguration中
往下翻 这里有根据读取了默认的cache配置
我们点击RedisCacheConfiguation中 可以看到一些默认配
我们模仿它这个配置文件将cache value设置为json格式
序列化格式为RedisSerializer key我们就是用默认配置的
value格式我们进入RedisSerializer类ctrl + h查看子类
将包换json的序列化器写入即可 因为我使用的是springboot自带的jackson 所以我就用GenericJackson2JsonRedisSerializer
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(RedisSerializer.string()))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));
这样一来我们的配置文件的配置项就失效了
查看源码 这一堆if语句用于读取默认的配置文件 而我们因为四自定义缓存配置 所以无法走到这里
我们可以模仿它的写法 将cacheProperties注入 根据cacheProperties获取配置文件并设置
@Configuration
public class RedisCacheConfig {
@Autowired
private CacheProperties cacheProperties;
@Bean
public RedisCacheConfiguration redisCacheConfiguration() {
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(RedisSerializer.string()))
.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.prefixCacheNameWith(redisProperties.getKeyPrefix());
}
if (!redisProperties.isCacheNullValues()) {
config = config.disableCachingNullValues();
}
if (!redisProperties.isUseKeyPrefix()) {
config = config.disableKeyPrefix();
}
return config;
}
}
@CacheEvict
删除缓存数据
@CacheEvict(value = "category", key = "'findCategoryByFirstCategory'")
删除分类为category key为findCategoryByFirstCategory的缓存
若删除多个缓存有两种方法
方法一:
使用@Caching
将批量执行的方法写入数组中
@Caching(evict = {
@CacheEvict(value = "category", key = "'findCategoryByFirstCategory'"),
@CacheEvict(value = "category", key = "'getCatalogJson'"),
})
方法二:
删除分区中的所有数据
将category分区下的缓存清楚
@CacheEvict(value = "category", allEntries = true)
我们将相同类型的业务逻辑放一起比如分类数据 放在分类下
当数据发生修改时 将整个分类分区下的数据删除即可
避免缓存穿透
将空数据存储到缓存中 并设置一个默认时间 避免缓存击穿
spring:
cache:
type: redis
redis:
cache-null-values: true
缓存击穿解决
查询缓存时添加一个同步sync 添加本地锁 当请求进入时锁住 避免大量请求查询服务 只有当前服务可以去查询数据库 计算是当前服务有100个 100个服务去查数据库 对系统影响也不是很大
@Cacheable(value = {"category"}, key = "#root.methodName", sync = true)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律