因为我们的热点数据也就是经常用到的数据,如果不加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就是一个这个框架。它利用了AOP,实现了基于注解的缓存功能,并且进行了合理的抽象,业务代码不用关心底层是使用了什么缓存框架,只需要简单地加一个注解,就能实现缓存功能了
添加依赖
- <dependency>
- <groupId>org.springframework.bootgroupId>
- <artifactId>spring-boot-starter-cacheartifactId>
- 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
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

选择Face的理由:
1、face是dubbo服务生
2、service的功能过于细腻,并且关联甚广
3、control层功能过于粗狂,不易缓存的维护
对于缓存声明,spring的缓存提供了一组java注解:
@Cacheable:触发缓存写入,如果缓存中没有:查询数据库,存储缓存,返回结果。如果缓存中有:直接返回缓存结果
@CacheEvict:触发缓存清除。
@CachePut:更新缓存(不会影响到方法的运行)。
@Caching:重新组合要应用于方法的多个缓存操作
==如果缓存中没有:查询数据库,存储缓存,返回结果,如果缓存中有:直接返回结果==
作用:可以用来进行缓存的写入,将结果存储在缓存中,以便于在后续调用的时候可以直接返回缓存中的值,而不必再执行实际的方法。 最简单的使用方式,注解名称=缓存名称,使用例子如下:

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

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

在使用缓存的时候,有可能会同时进行更新和删除,会出现同时使用多个注解的情况.而@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】=