Spring cache

基础概念

image
有CacheManager来管理缓存 缓存管理器中根据不同的业务来将不同的缓存进行分区

源码

可以查看CacheAutoConfiguration来查看spring cache自动配置了哪些东西
image
image
CacheProperties.class类中保存spring cache在yaml或properties中配置项
image
这里将不同的缓存类型添加到配置中
缓存类型如: redis 内存等
cacheType类如下
image
进入cacheConfiguration中 有块static语句块 根据不同
image
这里根据传入的缓存类型的不同 进行赋值
image
这里自动配置已经将缓存管理器创建好了

配置

首先导入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文档中有些
image

自定义缓存配置

首先查看源码进入到CacheAutoConfiguration 自动配置
配置中有个方法 这个方法是根据传入的缓存类型将缓存类型添加到配置中 我们跳转掉CacheConfigurations中
image
可以看到可支持的配置 我们使用的是redis 我们进入到RedisCacheConfiguration中
image
往下翻 这里有根据读取了默认的cache配置
image
我们点击RedisCacheConfiguation中 可以看到一些默认配
image

我们模仿它这个配置文件将cache value设置为json格式
序列化格式为RedisSerializer key我们就是用默认配置的
value格式我们进入RedisSerializer类ctrl + h查看子类
image
将包换json的序列化器写入即可 因为我使用的是springboot自带的jackson 所以我就用GenericJackson2JsonRedisSerializer

        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(RedisSerializer.string()))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));

这样一来我们的配置文件的配置项就失效了
查看源码 这一堆if语句用于读取默认的配置文件 而我们因为四自定义缓存配置 所以无法走到这里
我们可以模仿它的写法 将cacheProperties注入 根据cacheProperties获取配置文件并设置
image

@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)
posted @   RainbowMagic  阅读(129)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示