Spring从3.1开始定义了org.springframework.cache.Cache
和 org.springframework.cache.CacheManager
接口来统一不同的缓存技术;并支持使用 JSR-107
注解简化我们开发;
提供支持多种缓存的实现。
主要接口有两个:
-
org.springframework.cache.Cache
:用于定义缓存的各种操作 -
org.springframework.cache.CacheManager
:用于管理各个cache缓存组件
常用注解:
@Cacheable 通常用于配置方法,将方法的返回结果注入到缓存对象中(保存缓存)
如果缓存中有,则不调用方法,如果缓存没有,才会调用方法,将结果放入缓存
@CacheEvict 可用于类或方法,用于清空缓存(删除缓存) (失效模式使用该注解)
@CachePut :
强制执行方法并将返回结果放入缓存,而不是像 @Cacheable
那样首先从缓存中寻找方法返回结果是否存在缓存 (不影响方法执行更新缓存) (双写模式使用该注解)
@Caching 组合以上多个操作
@CacheConfig 用于对类进行配置,对整个类的缓存进行配置,可用 @Cacheable
取代
@EnableCaching 用于SpringBoot的启动类,开启注解功能
使用:
<dependency>
<groupId>org.springframework.b oot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
spring:
cache:
#指定缓存类型为redis
type: redis
redis:
# 指定redis中的过期时间为1h
time-to-live: 3600000
默认行为:
》如果缓存中有,方法不会被调用
》 key默认自动生成:缓存的名字:SimpleKey
》缓存的value值,默认使用jdk序列化机制,将序列化后的数据存到redis
》默认ttl时间:-1,也就是永不过期
自定义:
>指定生成的缓存的key 使用注解里面的属性key来指定 key=" 'xxx' " 需要加上单引号,
否则会认为是一个表达式,还有一个value是配置key的分区,(在spring中,redis没有)
>缓存的value保存为json格式
>设置key的过期时间 :上面的配置文件中已经配置了
配置value的json格式
@Configuration
@EnableConfigurationProperties(CacheProperties.class)
public class MyCacheConfig {
//方法参数会通过注入的方式传入,当然我们也可以使用变量的方式写来注入
@Bean
public RedisCacheConfiguration redisCacheConfiguration( CacheProperties cacheProperties) {
CacheProperties.Redis redisProperties = cacheProperties.getRedis();
org.springframework.data.redis.cache.RedisCacheConfiguration config = org.springframework.data.redis.cache.RedisCacheConfiguration
.defaultCacheConfig();
//指定缓存序列化方式为json
config = config.serializeValuesWith(
RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));
//下面的这四个配置,如果我们不写在这里的话,将读取不到。默认的配置也会有的,但是我们自己写配置类的话,就需要加上去,
//设置配置文件中的各项配置,如过期时间
if (redisProperties.getTimeToLive() != null) {
config = config.entryTtl(redisProperties.getTimeToLive());
}
//key的前缀
if (redisProperties.getKeyPrefix() != null) {
config = config.prefixKeysWith(redisProperties.getKeyPrefix());
}
//是否缓存空值
if (!redisProperties.isCacheNullValues()) {
config = config.disableCachingNullValues();
}
//是否使用key的前缀
if (!redisProperties.isUseKeyPrefix()) {
config = config.disableKeyPrefix();
}
return config;
}
}
//注意,通过源码发现,自己配置类的话,需要将配置文件的配置在这里进行配置,否则不会生效,比如过期时间,前缀等。
当然配置了这些,配置文件里面肯定是不可少的
spring.cache.redis.cache-null-values=true
spring.cache.redis.key-prefix=xxx
spring.cache.redis.use-key-prefix=true
在加上上面的配置的过期时间。
还有就是要注意的是,
之前我们说了@Cacheable()注解,他的value是配置的key的分区名称,
如果我们在配置文件spring.cache.redis.key-prefix里面配置的前缀会覆盖注解里配置的分区。
如果spring.cache.redis.use-key-prefix为false的话,则两边的配置前缀都不会生效,也就是没有前缀
建议:
同一类型的数据使用相同的1分区名,方便删除更新
在配置文件中不设置前缀,同一使用注解的value分区名称作为前缀
那么spring cache如何解决缓存穿透,缓存击穿,缓存雪崩
其中,缓存穿透我们在配置文件中,设置了可以缓存null值,所以就相当于解决了
缓存雪崩的话,由于在配置文件中加了key的过期时间,由于程序的时间线不一样,统一的过期时间设置能达到kry的不同失效时间,
而缓存击穿的话,就是在@Cacheable(sync=true)该注解上加上该属性,就可以了,
其内部就是一个本地的一个synchroized锁,判断没有值,则开一个线程任务去数据库获取值,然后将值设置进缓存中返回。
写模式:写多读多,或者写多读少,建议直接·使用数据库,不使用缓存,
或者使用canal