Spring Cache和redis结合使用

时间:2024-10-14 20:43:59
  1. <dependency>
  2. <groupId></groupId>
  3. <artifactId>spring-boot-starter-cache</artifactId>
  4. </dependency>
  5. <dependency>
  6. <groupId></groupId>
  7. <artifactId>spring-boot-starter-data-redis</artifactId>
  8. </dependency>

2.2配置文件

  1. #名字可以自动配置
  2. #-names=qq
  3. =redis
  4. #设定数据存活时间1小时
  5. -to-live=3600000
  6. #key的前缀
  7. -prefix=CACHE_
  8. #key是否用前缀
  9. -key-prefix=false
  10. #是否缓存空值,防止缓存穿透
  11. -null-values=true

2.3自行配置RedisCacheConfiguration(如果不配置需要将@EnableCaching放到启动类上)

  1. package ;
  2. import ;
  3. import ;
  4. import ;
  5. import ;
  6. import ;
  7. import ;
  8. import ;
  9. import ;
  10. import ;
  11. @EnableConfigurationProperties()
  12. @Configuration
  13. @EnableCaching
  14. public class MyCacheConfig {
  15. @Bean
  16. RedisCacheConfiguration redisCacheConfiguration(CacheProperties cacheProperties){
  17. RedisCacheConfiguration config = ();
  18. //设置key用string类型保存,value用json格式保存
  19. config = ((new StringRedisSerializer()));
  20. config = ((new GenericFastJsonRedisSerializer()));
  21. CacheProperties.Redis redisProperties = ();
  22. //使配置文件中所有的配置都生效
  23. if (() != null) {
  24. config = (());
  25. }
  26. if (() != null) {
  27. config = (());
  28. }
  29. if (!()) {
  30. config = ();
  31. }
  32. if (!()) {
  33. config = ();
  34. }
  35. return config;
  36. }
  37. }

2.4使用注解操作

  1. /**
  2. * 每一个需要缓存的数据都要指定要放到哪个名字的缓存。【缓存的分区(按照业务类型分)】
  3. * 代表当前方法的结果需要缓存,如果缓存中有,方法不会调用,如果缓存中没有,会调用方法。并将方法的结果放入缓存
  4. * 默认行为
  5. * 1)如果缓存中有,方法不再调用
  6. * 2)key是默认生成的:缓存的名字::SimpleKey::[](自动生成key值)
  7. * 3)缓存的value值,默认使用jdk序列化机制,将序列化的数据存到redis中
  8. * 4)默认ttl时间是 -1:
  9. *
  10. * 用户自行操作:key的生成
  11. * 1)指定生成缓存的key:key属性可以指定,接收一个Spel
  12. * 2)指定缓存的数据的存活时间:配置文档中修改存活时间
  13. * 3)将数据保存为json格式
  14. * CacheAutoConfiguration->RedisCacheConfiguration->自动配置了RedisCacheManager->初始化所有的缓存
  15. * -》每个缓存决定使用什么配置->如果redisCacheConfiguration有就用已有的,没有就用默认的配置->想改缓存配置,只需给容器
  16. * 中放一个RedisCacheConfiguration即可->就会应用到当前RedisCacheManager管理的所有缓存分区中
  17. *
  18. */
  19. @Cacheable(value={"category"},key="#",sync = true)
  20. @Override
  21. public List<CategoryEntity> getLevel1Categorys() {
  22. return this.(new QueryWrapper<CategoryEntity>().eq("parent_cid",0));
  23. }

2.5访问redis数据库

2.6再添加两个方法

  1. @Cacheable(value = "category",key="#")
  2. @Override
  3. public Map<String, List<Catelog2Vo>> getCatelogJson() {
  4. //业务操作。。。
  5. }
  1. //多项操作时用@Caching
  2. @Caching(evict = {
  3. @CacheEvict(value = "category",key="'getLevelCategorys'"),
  4. @CacheEvict(value = "category",key="'getCatelogJson'")
  5. })
  6. @Transactional
  7. @Override
  8. public void updateCascade(CategoryEntity category) {
  9. this.updateById(category);
  10. (());
  11. (());
  12. ((),());
  13. }

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) //删除某个分区下的所有数据

可以获得同样的效果。

同时,将配置文件替换成:

  1. #名字可以自动配置
  2. #-names=qq
  3. =redis
  4. #设定数据存活时间1小时
  5. -to-live=3600000
  6. #key的前缀
  7. #-prefix=CACHE_
  8. #key是否用前缀
  9. -key-prefix=true
  10. #是否缓存空值,防止缓存穿透
  11. -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负责缓存的读写

相关文章