Spring专门对缓存的一个抽象层
1. 引入依赖
spring-boot-starter-cache
spring-boot-starter-data-redis
2. 写配置
在application中配置使用的那个缓存
spring.cache.type=redis
2.1 缓存的名字
可以不配置,会自动生成,
如果配置,会禁用实时的创建这个名字的功能,
以后只会使用你配置的名字
3. 测试使用缓存
//触发将数据保存到缓存的操作
@Cacheable: Triggers cache population.
//触发将数据从缓存删除的操作--redis失效模式进行缓存更新
@CacheEvict: Triggers cache eviction.
//不影响方法执行更新缓存--redis双写模式进行缓存更新
@CachePut: Updates the cache without interfering with the method execution.
//组合以上操作
@Caching: Regroups multiple cache operations to be applied on a method.
//在类级别共享缓存的相同配置
@CacheConfig: Shares some common cache-related settings at class-level.
3.1 使用缓存
-
开启缓存功能
@EnableCaching 注解使用在主启动类上
-
只需要使用注解就可以操作缓存–默认设置
-
@Cacheable //代表当前的结果需要缓存-位置方法上
如果缓存中有,方法不调用,如果没有,就会调用方法,将方法的结果放入缓存
-
每一个需要缓存的数据,我们都来指定要放到哪个名字的缓存中
@Cacheable(value=“item”)
-
3.2 默认行为
- 如果缓存中有,方法不调用
- redis中的key默认自动生成
- redis缓存中的值,默认使用jdk序列化机制,将序列化后的数据存到redis中
- 默认ttl时间 -1 永不过期
3.3 *自定义行为
- 指定生成缓存需要的key, 使用注解的key属性,接收一个SpEL,所以不能直接用key的名字,需要加上单引号
//指定缓存分区,和缓存的key名称
@Cacheable(value="item",key="'selectItem'")
@GetMapping("/getItem")
public R selectItem(){
}
名称 | 地点 | 描述 | 例子 |
---|---|---|---|
methodName | root | 被调用方法的名称 | #root.methodName |
method | root | 被调用的方法 | #root.method.name |
target | root | 被调用的目标对象 | #root.target |
targetClass | root | 被调用目标的类 | #root.targetClass |
args | root | 用于调用目标的参数(作为数组) | #root.args[0] |
caches | root | 运行当前方法的缓存集合 | #root.caches[0].name |
参数名称 | 评价背景 | 任何方法参数的名称。如果名称不可用(可能是由于没有调试信息),则参数名称也可在代表参数索引的#a<#arg> where下#arg (从 开始0 )。 | #iban or #a0 (您也可以使用#p0 or#p<#arg> 符号作为别名)。 |
result | 评价背景 | 方法调用的结果(要缓存的值)。仅在unless 表达式、cache put 表达式(用于计算key )或cache evict 表达式(何时beforeInvocation 是false )中可用。对于支持的包装器(例如 Optional ),#result 指的是实际对象,而不是包装器。 | #result |
- 指定缓存中数据的存活时间
在application配置文件中设置过期时间
//单位毫秒--10000毫秒是10秒
spring.cache.redis.time-to-live=10000
- 指定redis中数据的value的类型为json格式
CacheAutoConfiguration缓存的自动配置类,
自动配置 会导入redis的缓存配置类RedisCacheConfiguration,
redis缓存配置类 会自动配置redis的缓存管理器RedisCacheManager
初始化所有的缓存
每个缓存觉得使用什么配置,如果RedisCacheConfiguration有就用, 没有就用自己的
如果想改缓存的配置, 就需要给容器汇总放一个RedisCacheConfiguration
@EnableCaching
@Configuration
public class MyRedisCacheConfig {
@Bean
RedisCacheConfiguration redisCacheConfiguration(){
//先使用默认配置,我们再进行修改
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
//设置缓存过期时间,单位分钟
config = config.entryTtl(Duration.ofMinutes(10));
//使用一个String类型的序列化key名称
config = config.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()));
//使用一个json类型的序列化value值Generic代表可以转换为对象的方式
config = config.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()))
return config;
}
}
删除缓存-更新缓存-失效模式
@CacheEvict(value="item",key="'selectItem'")//缓存更新-失效模式
//删除缓存,缓存的分区和redis中key的名字都需要指定,之前存入的是那种现在就是那种
public R updateItem(String id){
}
组合操作
如果,更新缓存需要删除两个缓存内容,一个页面的一个后台的,则需要使用@Caching组合操作,删除两个缓存
@Caching(evict = {
//删除两个缓存的操作
@CacheEvict(value = "item",key = "'cacheItem'"),
@CacheEvict(value = "item",key = "'getCacheItem'"),
})
//或者
//删除item分区里面的所有数据
//同一种类型的数据,可以存同一分区, 当我们修改了这个类型的数据,那么我们就可以直接删除这个类型的所有
//以后我们不要指定前缀,就用他的分区名称作为前缀--默认不写即可
@CacheEvict(value = "item",allEntries = true)
缓存雪崩,这里就不用设置随机的过期时间,
因为你加入缓存的时间不一致,直接导致,你的过期时间是不同的
Spring cache 解决缓存问题
写模式-保证缓存与数据库一致
- 读多: 读写加锁
- 引入中间件Canal,感知到mysql的更新,去更新缓存
- 读多写多, 直接去数据库,不通过缓存
读模式
-
缓存穿透: 查询一个null的数据, 解决: 缓存空值,cache解决,配置文件配置
cache: redis: cache-null-values: true # 缓存空值
-
缓存击穿: 大量查询一个将要过期的值, 解决:加锁访问数据库,
//cacheable注解可以使用本地锁,一般来说,本地锁够用了 @Cacheable(value="item",key="'selectItem'",sync=true)
-
缓存雪崩: 大量缓存失效, 解决: 加上随机过期时间, 在cache中只需要添加过期时间即可, 你加入的缓存时间不同, 那么,你失效的时间也会不同
总结
- 常规数据: 直接使用springCache就可以满足了
- 特殊数据: 特殊设计, 自己写如何存入缓存,如何失效, 如何保证数据一致性, 分布式锁,