一篇搞定Spring Cache

使用方法(教程)

1.引入依赖
    dependency
        groupIdorg.springframework.bootgroupId
        artifactIdspring-boot-starter-cacheartifactId
    dependency
2.开启cache功能
也就是在配置类上添加@EnableCaching
3.springcache的几个注解和作用
  • @Cacheable Triggers cache population.(触发缓存填充)

    In the preceding snippet, the findBook method is associated with the cache named books. Each time the method is called,
    the cache is checked to see whether the invocation has already been run and does not have to be repeated. While in most cases,
    only one cache is declared, the annotation lets multiple names be specified so that more than one cache is being used. In this case,
    each of the caches is checked before invoking the method — if at least one cache is hit,the associated value is returned.
    
    在前面的代码片段中,findBook方法与名为books的缓存相关联。每次调用该方法时,都会检查缓存以查看调用是否已经运行并且不必重复。虽然在大多数情况下,只声明一个缓存,
    但注释允许指定多个名称,以便使用多个缓存。在这种情况下,在调用方法之前检查每个缓存—如果至少命中一个缓存,则返回相关值。
    
    @Cacheable({books, isbns})
    public Book findBook(ISBN isbn) {...}
    
  • @CacheEvict Triggers cache eviction.(触发缓存清除)

        When the cache needs to be updated without interfering with the method execution, you can use the @CachePut annotation.
     That is, the method is always invoked and its result is placed into the cache (according to the @CachePut options). 
     It supports the same options as @Cacheable and should be used for cache population rather than method flow optimization.
     The following example uses the @CachePut annotation
     当需要在不干扰方法执行的情况下更新缓存时,可以使用@CachePut注释。也就是说,总是调用该方法并将其结果放入缓存中(根据@CachePut选项)。
     它支持与@Cacheable相同的选项,应该用于缓存填充而不是方法流优化。下面的例子使用了@CachePut注释
    
    @CachePut(cacheNames=book, key=#isbn)
    public Book updateBook(ISBN isbn, BookDescriptor descriptor)
    
  • @CachePut Updates the cache without interfering with the method execution.(在不干扰方法执行的情况下更新缓存)

         The cache abstraction allows not just population of a cache store but also eviction. 
      This process is useful for removing stale or unused data from the cache. As opposed to @Cacheable,
      @CacheEvict demarcates methods that perform cache eviction (that is, methods that act as triggers for removing data from the cache).
      Similarly to its sibling, @CacheEvict requires specifying one or more caches that are affected by the action,
      allows a custom cache and key resolution or a condition to be specified, 
      and features an extra parameter (allEntries) that indicates whether a cache-wide eviction needs to be performed rather than just an entry eviction (based on the key). 
      The following example evicts all entries from the books cache
      缓存抽象不仅允许填充缓存存储,还允许删除缓存存储。此过程用于从缓存中删除过时或未使用的数据。与@Cacheable相反,@CacheEvict定义了执行缓存清除的方法(即充当从缓存中删除数据的触发器的方法)。与它的兄弟类似,
      @CacheEvict需要指定一个或多个受动作影响的缓存,允许自定义缓存和键解析或指定条件,并具有一个额外的参数(allEntries),表明是否需要在缓存范围内清除
    
    @CacheEvict(cacheNames=books, allEntries=true)
    public void loadBooks(InputStream batch)
    
  • @Caching Regroups multiple cache operations to be applied on a method.(将应用于方法的多个缓存操作重新分组)

      Sometimes, multiple annotations of the same type (such as @CacheEvict or @CachePut) need to be specified — for example, 
    because the condition or the key expression is different between different caches. @Caching lets multiple nested @Cacheable,
    @CachePut, and @CacheEvict annotations be used on the same method. The following example uses two @CacheEvict annotations
    有时,需要指定相同类型的多个注释(例如@CacheEvict或@CachePut)—例如,因为不同缓存之间的条件或键表达式不同。@Caching允许在同一个方法上使用多个嵌套的@Cacheable、@CachePut和@CacheEvict注释。
    下面的例子使用了两个@CacheEvict注释
    
    @Caching(evict = { @CacheEvict(primary), @CacheEvict(cacheNames=secondary, key=#p0) })
    public Book importBooks(String deposit, Date date)
    
  • @CacheConfig Shares some common cache-related settings at class-level.(在类级别共享一些常见的与缓存相关的设置)

       So far, we have seen that caching operations offer many customization options and that you can set these options for each operation. 
    However, some of the customization options can be tedious to configure if they apply to all operations of the class. For instance, 
    specifying the name of the cache to use for every cache operation of the class can be replaced by a single class-level definition. 
    This is where @CacheConfig comes into play. The following examples uses @CacheConfig to set the name of the cache
    到目前为止,我们已经看到缓存操作提供了许多自定义选项,您可以为每个操作设置这些选项。但是,如果一些自定义选项适用于类的所有操作,那么配置起来可能会很繁琐。
    例如,指定要用于类的每个缓存操作的缓存的名称可以用单个类级别定义代替。这就是@CacheConfig发挥作用的地方。下面的例子使用@CacheConfig来设置缓存的名称
    
    @CacheConfig(books) 
    public class BookRepositoryImpl implements BookRepository {
    
        @Cacheable
        public Book findBook(ISBN isbn) {...}
    }
    

springCache的相关配置

springCache默认保存key、value的形式为使用java原生的序列化方式,我们想要以json的形式保存数据就要做相应的配置

对应源码:
在这里插入图片描述

我们需要修改配置,根据RedisSerializer对RedisCacheConfiguration当中的序列化value的的序列化器进行修改。

实现RedisSerializer接口的类:
在这里插入图片描述

下面是配置类的代码:

@EnableCaching
@Configuration
@EnableConfigurationProperties(CacheProperties.class)
public class cacheConfig {

    @Bean
    public RedisCacheConfiguration redisCacheConfiguration(CacheProperties cacheProperties){
        //拿到默认的RedisCacheConfiguration
        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;
    }
}

分析springCache是否存在问题

1.读的情况下:
缓存穿透:
    在某一瞬间大量查询数据库中的空数据。springCache针对于缓存穿透提供了解决方案,就是添加配置   
      spring.cache.redis.cache-null-values=true
缓存雪崩:
    在某一个瞬间大量缓存都失效。springCache也提供了相应的解决方案。需要添加配置:
      spring.cache.redis.time-to-live=3600000
缓存击穿:
      某个热点数据缓存失效的瞬间有大量请求获取数据,直接导致数据库的压力变大。解决此问题的方案就是再查询数据库的时候添加锁。
    在分布式的情况下往往使用resisson。springCache也提供了一种解决方案:
      @Cacheable(value = category,key =#root.method.name,sync = true)
    其中sync = true相当对从数据库当中获取数据这一步骤添加上锁。对于实时性不强的微服务项目也是可以使用的。
2.写的情况下:(缓存与数据的一致性)
读写锁
引入canal,感知到mysql的变化去改变缓存区的数据
读多写多的数据直接存入数据库,不写缓存

总结

读多写少,实时性、一致性不高的数据完全可以使用springCache;对于特殊的数据要特殊处理

更详细的需要参考官方文档:springCache官方文档

  • 24
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小魏苦练算法

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值