-
<dependency>
-
<groupId></groupId>
-
<artifactId>spring-boot-starter-cache</artifactId>
-
</dependency>
-
<dependency>
-
<groupId></groupId>
-
<artifactId>spring-boot-starter-data-redis</artifactId>
-
</dependency>
2.2配置文件
-
#名字可以自动配置
-
#-names=qq
-
=redis
-
#设定数据存活时间1小时
-
-to-live=3600000
-
#key的前缀
-
-prefix=CACHE_
-
#key是否用前缀
-
-key-prefix=false
-
#是否缓存空值,防止缓存穿透
-
-null-values=true
2.3自行配置RedisCacheConfiguration(如果不配置需要将@EnableCaching放到启动类上)
-
package ;
-
-
import ;
-
import ;
-
import ;
-
import ;
-
import ;
-
import ;
-
import ;
-
import ;
-
import ;
-
-
@EnableConfigurationProperties()
-
@Configuration
-
@EnableCaching
-
public class MyCacheConfig {
-
@Bean
-
RedisCacheConfiguration redisCacheConfiguration(CacheProperties cacheProperties){
-
-
RedisCacheConfiguration config = ();
-
//设置key用string类型保存,value用json格式保存
-
config = ((new StringRedisSerializer()));
-
config = ((new GenericFastJsonRedisSerializer()));
-
-
CacheProperties.Redis redisProperties = ();
-
//使配置文件中所有的配置都生效
-
if (() != null) {
-
config = (());
-
}
-
if (() != null) {
-
config = (());
-
}
-
if (!()) {
-
config = ();
-
}
-
if (!()) {
-
config = ();
-
}
-
-
return config;
-
}
-
}
2.4使用注解操作
-
/**
-
* 每一个需要缓存的数据都要指定要放到哪个名字的缓存。【缓存的分区(按照业务类型分)】
-
* 代表当前方法的结果需要缓存,如果缓存中有,方法不会调用,如果缓存中没有,会调用方法。并将方法的结果放入缓存
-
* 默认行为
-
* 1)如果缓存中有,方法不再调用
-
* 2)key是默认生成的:缓存的名字::SimpleKey::[](自动生成key值)
-
* 3)缓存的value值,默认使用jdk序列化机制,将序列化的数据存到redis中
-
* 4)默认ttl时间是 -1:
-
*
-
* 用户自行操作:key的生成
-
* 1)指定生成缓存的key:key属性可以指定,接收一个Spel
-
* 2)指定缓存的数据的存活时间:配置文档中修改存活时间
-
* 3)将数据保存为json格式
-
* CacheAutoConfiguration->RedisCacheConfiguration->自动配置了RedisCacheManager->初始化所有的缓存
-
* -》每个缓存决定使用什么配置->如果redisCacheConfiguration有就用已有的,没有就用默认的配置->想改缓存配置,只需给容器
-
* 中放一个RedisCacheConfiguration即可->就会应用到当前RedisCacheManager管理的所有缓存分区中
-
*
-
*/
-
@Cacheable(value={"category"},key="#",sync = true)
-
@Override
-
public List<CategoryEntity> getLevel1Categorys() {
-
return this.(new QueryWrapper<CategoryEntity>().eq("parent_cid",0));
-
}
2.5访问redis数据库
2.6再添加两个方法
-
@Cacheable(value = "category",key="#")
-
@Override
-
public Map<String, List<Catelog2Vo>> getCatelogJson() {
-
//业务操作。。。
-
}
-
//多项操作时用@Caching
-
@Caching(evict = {
-
@CacheEvict(value = "category",key="'getLevelCategorys'"),
-
@CacheEvict(value = "category",key="'getCatelogJson'")
-
})
-
@Transactional
-
@Override
-
public void updateCascade(CategoryEntity category) {
-
this.updateById(category);
-
(());
-
(());
-
((),());
-
}
2.7运行测试
先执行getLevel1Categorys()和getCatelogJson()两个方法,可以看到redis数据库里存了它们缓存的数据
接着运行 updateCascade()方法,则数据消失了。@Caching可同时进行多项操作,@CacheEvict可以删除指定的缓存。
补充:将
@Caching(evict = { @CacheEvict(value = "category",key="'getLevelCategorys'"), @CacheEvict(value = "category",key="'getCatelogJson'") })
替换成
@CacheEvict(value = "category",allEntries = true) //删除某个分区下的所有数据
可以获得同样的效果。
同时,将配置文件替换成:
-
#名字可以自动配置
-
#-names=qq
-
=redis
-
#设定数据存活时间1小时
-
-to-live=3600000
-
#key的前缀
-
#-prefix=CACHE_
-
#key是否用前缀
-
-key-prefix=true
-
#是否缓存空值,防止缓存穿透
-
-null-values=true
执行执行getLevel1Categorys()和getCatelogJson()两个方法,可以看到数据库里两个缓存数据归类到category下面:
3、SpringCache的不足之处
1)、读模式
缓存穿透:查询一个null数据。解决方案:缓存空数据。
-null-values=true
缓存击穿:大量并发进来同时查询一个正好过期的数据。解决方案:加锁 ? 默认是无加锁的;使用sync = true来解决击穿问题。
@Cacheable(value={"category"},key="#",sync = true)
缓存雪崩:大量的key同时过期。解决:加随机时间。加上过期时间。
-to-live=3600000
2)、写模式:(缓存与数据库一致)
读写加锁。
引入Canal,感知到MySQL的更新去更新Redis
读多写多,直接去数据库查询就行
4、总结
常规数据(读多写少,即时性,一致性要求不高的数据,完全可以使用Spring-Cache):写模式(只要缓存的数据有过期时间就足够了)
原理:CacheManager(RedisCacheManager)->Cache(RedisCache)->Cache负责缓存的读写