SpringCache

为什么使用缓存 ?

因为我们的热点数据也就是经常用到的数据,如果不加redis缓存我们用户经常访问这些数据,就会经常访问mysql,但是MySQL数据是存在硬盘中的就会走IO,这时候我们可以将这些数据放到缓存中,如果缓存有就去缓存拿如果缓存没有就去MySQL,这样可以提高效率

 缓存穿透

缓存和数据库中都没有的数据,那么这时候数据来访问redis缓存,当查数据时发现reids缓存没有去查询MySQL,导致每次查这个数据都去数据库查询,这样就像redis缓存被穿透了,MySQL大量过来请求导致宕机。

解决方案:   

1 使用限流   

2 创建一个空的,key:1   value:null   这样访问第一次发现数据库没有就保持这个key的value设置为null    但是这个设置的过期时间短一点,防止MySQL已经存在该数据了还是返回的null

3 使用布隆过滤器存储可能访问的key,当不存在这个key时就会把这个请求过滤

缓存击穿

当MySQL有这个数据但是redis没有这个数据,如果多个用户都来访问这个热点数据,导致大量用户并发读取缓存发现没有这个数据,同时去MySQL中读取,导致的数据库压力增大

解决方案:
1  热值热点数据永不过期     由定时任务定时更新缓存

2 添加互斥锁   同一时间只能有一个用户来访问,但是会导致变成单线程

缓存雪崩

大量的热点数据在同一时间过期,导致数据访问时发现缓存中key已经过期了,热点数据的访问很多都去MySQL中访问了,导致了MySQL请求量增大

解决方式:
1      过期时间打散,将热点数据的过期时间不弄在一起

2      缓存分布式       将数据均匀分布到不同的缓存数据库中

3      热点数据不过期      热点的数据不过期这样就防止了同一时间热点数据过期

4    添加互斥锁    该方式和缓存击穿一样,按 key 维度加锁,对于同一个 key,只允许一个线程去计算,其他线程原地阻塞等待第一个线程的计算结果,然后直接走缓存即可。

spring-cache概述及核心配置

Spring Cache就是一个这个框架。它利用了AOP,实现了基于注解的缓存功能,并且进行了合理的抽象,业务代码不用关心底层是使用了什么缓存框架,只需要简单地加一个注解,就能实现缓存功能了

使用步骤

添加依赖

<!--springboot的cache支持-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>

添加配置

package com.itheima.restkeeper.config;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.time.Duration;


/**
 * @ClassName RedisCacheConfig.java
 * @Description redis配置
 */
@Configuration
//开启caching的支持
@EnableCaching
public class RedisCacheConfig {


    /**
     * 申明缓存管理器,会创建一个切面(aspect)并触发Spring缓存注解的切点(pointcut)
     * 根据类或者方法所使用的注解以及缓存的状态,这个切面会从缓存中获取数据,
     * 将数据添加到缓存之中或者从缓存中移除某个值
     * @return
     */
    @Bean
    public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
        //对key的序列化操作:String
        RedisSerializer<String> redisSerializer = new StringRedisSerializer();
        //对value的序列化操作:json
        GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer =
                new GenericJackson2JsonRedisSerializer();
        //配置config,指定超时时间记得key val 序列化处理
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                //指定全局超时时间【60S】
                .entryTtl(Duration.ofSeconds(60))
                //配置key的序列化方式
                .serializeKeysWith(RedisSerializationContext
                        .SerializationPair
                        .fromSerializer(redisSerializer))
                //配置value的序列化方式
                .serializeValuesWith(RedisSerializationContext
                        .SerializationPair
                        .fromSerializer(genericJackson2JsonRedisSerializer))
                //关闭空值的存储
                .disableCachingNullValues();

        //使用建造者进行初始化
        return RedisCacheManager.builder(redisConnectionFactory)
                .cacheDefaults(config)
                .build();
    }
}

配置类

#spring相关配置
spring:
  main:
    allow-bean-definition-overriding: true
  redis:
    redisson:
      config: classpath:singleServerConfig.yaml
    #redis配置信息  
    host: 192.168.112.77
    port: 6379
    password: pass

优雅使用spring-cache

选择Face的理由:

1、face是dubbo服务生

2、service的功能过于细腻,并且关联甚广

3、control层功能过于粗狂,不易缓存的维护

 注解

对于缓存声明,spring的缓存提供了一组java注解:

  • @Cacheable:触发缓存写入,如果缓存中没有:查询数据库,存储缓存,返回结果。如果缓存中有:直接返回缓存结果

  • @CacheEvict:触发缓存清除。

  • @CachePut:更新缓存(不会影响到方法的运行)。

  • @Caching:重新组合要应用于方法的多个缓存操作

2.1、@Cacheable注解

==如果缓存中没有:查询数据库,存储缓存,返回结果,如果缓存中有:直接返回结果==

作用:可以用来进行缓存的写入,将结果存储在缓存中,以便于在后续调用的时候可以直接返回缓存中的值,而不必再执行实际的方法。 最简单的使用方式,注解名称=缓存名称,使用例子如下:

2.2、@CacheEvict注解

@CacheEvict:删除缓存的注解,这对删除旧的数据和无用的数据是非常有用的。这里还多了一个参数(allEntries),设置allEntries=true时,可以对整个条目进行批量删除

2.3、@CachePut注解

@CachePut:当需要更新缓存而不干扰方法的运行时 ,可以使用该注解。也就是说,始终执行该方法,并将结果放入缓存

2.4、@Caching注释

在使用缓存的时候,有可能会同时进行更新和删除,会出现同时使用多个注解的情况.而@Caching可以实现

//添加user缓存的同时,移除userPage的缓存
@Caching(put =@CachePut(value = "user",key ="#userVo.id"),
        evict = @CacheEvict(value = "userPage",allEntries = true))

==使用的规则:==

==1、项目启动时候需要增加哪些数据的热加载,以方便查询时候直接使用【@Cacheable】==

==2、增删改更新缓存【@CachePut,@CacheEvict】,查使用缓存【@Cacheable】==

==3、复杂场景中需要执行多条命令时候使用【@Caching】=

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值