当前位置: 首页 > news >正文

@cacheable 是否缓存成功_让我们来学习学习SpringCache分布式缓存,为什么用?

Spring Cache

简介

  • Cache接口为缓存的组件规范定义,包含缓存的各种操作集合
  • Cache接口下Spring提供了各种xxcache的实现;如RedisCache,EhCacheCache,ConcurrentMapCache等;
  • 每次调用需要缓存功能的方法时,Spring会检查检查指定参数的指定的目标方法是否已经被调用过;如果有就直接从缓存中获取方法调用后的结果,如果没有就调用方法并缓存结果后返回给用户。下次调用直接从缓存中获取。

63847739e88085d1f14ca5b853f53cd4.png

引入依赖

<!--引入spring cache-->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-cache</artifactId>
		</dependency>

配置

spring.cache.type=redis

开启注解

@EnableCaching

常用注解

  • @Cacheable:触发操作将数据保存到缓存中,参数value指cacheName
  • @CacheEvict:触发操作将数据从缓存中删除(运用于失效模式)
  • @CachePut:不影响方法执行更新(运用于双写模式)
  • @Caching:组合以上多个操作
  • @CacheConfig:再类级别上共享有关缓存的配置

默认配置

  • key自动生成:缓存名字::SimpleKey[]
  • value默认是jdk序列化
  • 默认ttl时间:-1
  • 默认查询数据如果缓存中存在,则不再调用方法,直接将缓存中命中的数据返回

自定义配置

d0e0b27d9a7365530d8035b2ea0d9c7c.png
  • 指定key:
    • key默认为spel表达式:#root.method.name指用方法名作为key保存在缓存中
      • @Cacheable(value="category",key="#root.methodName")

3f5d5a2dba0352eb7b2708204897faf7.png
    • key是字符串的话额外要加单引号(默认会做表达式解析)
      • @Cacheable(value=“category”,key=“‘catalogJson-cache’”)
    • 缓存key表达为:
      • 指定前缀(前提:有指定前缀并且开启了使用前缀)+指定key名

fd18b4c4f6cf6f50b945e3e41c33e9ef.png
      • 推荐: 默认前缀(缓存名字,前提:允许使用前缀,没有指定前缀):: key名字 (并且保存在以指定的缓存名字namespace下,树形结构显示)

a1abe67adc6c7f7c9722dc6e3c78f84e.png
      • key名字(前提:无前缀)

62ac115847c63a42318a1bc7f61c700f.png
  • 指定其他信息
    spring.cache.type=redis #指定ttl,单位必需(m,s,h,d) spring.cache.redis.time-to-live=3600000m spring.cache.redis.key-prefix=CACHE_ spring.cache.redis.use-key-prefix=true #默认允许缓存空值->解决缓存穿透问题,暂时性保存null给其他并发线程返回,以保护数据库 spring.cache.redis.cache-null-values=true
  • 将value改为json格式(默认Jdk序列化器)
    Redis序列化器:

9a7ff7cf94831bf136b82374d1d8eeae.png
@EnableCaching
@Configuration
public class MyCacheConfig {

    @Bean
    RedisCacheConfiguration cacheConfiguration(CacheProperties cacheProperties){
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
        //entryTtl方法返回一个新的RedisCacheConfiguration对象覆盖原有对象,其他属性方法也是如此
        //cacheConfig=cacheConfig.entryTtl()
        //config = config.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()));
        config = config.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));

        //整合配置文件(不整合配置文件所配置的内容不生效)
        //取出配置信息
        CacheProperties.Redis redisProperties = cacheProperties.getRedis();

        if (redisProperties.getTimeToLive() != null) {
            config = config.entryTtl(redisProperties.getTimeToLive());
        }

        if (redisProperties.getKeyPrefix() != null) {
            config = config.prefixKeysWith(redisProperties.getKeyPrefix());
        }

        if (!redisProperties.isCacheNullValues()) {
            config = config.disableCachingNullValues();
        }

        if (!redisProperties.isUseKeyPrefix()) {
            config = config.disableKeyPrefix();
        }

        return config;
    }

}

更新缓存数据

1、@CacheEvict

用于缓存失效模式:修改后删除该缓存信息

@CacheEvict 是用来标注在需要清除缓存元素的方法或类上的

  • 单个删除:
    在方法上标注(一般为保存,更新方法)@CacheEvict(value="category",key="'getLevel1Categories'")
    表示一旦执行该方法则会从缓存中删除对应的key
  • 批量删除:
  1. @Caching批量操作
    @Caching(evict = { @CacheEvict(value="category",key="'getLevel1Categories'"), @CacheEvict(value="category",key="'getCatalogJson'") })
  2. 删除整个namespace(一般统一类型的数据存放在同一个分区中)@CacheEvict(value="category",allEntries = true)
  • allEntries:默认为false,当其为true时表示清除缓存中的所有元素
  • beforeInvocation:默认是false,表示执行方法后删除(当方法如果因为抛出异常而未能成功返回时也不会触发清除操作),当指定该属性值为true时,Spring会在调用该方法之前清除缓存中的指定元素。

2、@CachePut

用于缓存双写模式:修改后立即写入缓存

@CachePut标注的方法在执行前不会去检查缓存中是否存在之前执行过的结果,而是每次都会执行方法,并将结果(方法返回值)存入指定的缓存中

造个轮子

我们经常说不要重复造轮子。为了开发效率,可以不造轮子,但是必须具备造轮子的能力。建议造一个简单的MQ,你能用到通信协议、设计模式、队列等许多知识。在造轮子的过程中,你会频繁的翻阅各种手册或者博客,这就是用输出倒逼输入。

dd22b9e1c4a59076bf6d6974114d8221.png

上面是我自己整理的一些学习资料,还有一些大公司面试题,比较干货,需要的朋友可以私信我回复‘资料’,或者点下方文档我可以免费分享。

石墨文档​shimo.im

相关文章:

  • zookeeper集群_Docker实战之Zookeeper集群
  • kibana 查看有多少索引库_kibana-1:使用timeline构建时间序列图
  • cordova打开外部链接_AutoCAD小秘密050:外部参照面面观(上)
  • asp.net通过webservice调用java接口全过程_springboot整合Feign实现远程接口调用
  • 检测到目标url存在框架注入漏洞_CVE201914234:Django JSONField SQL注入漏洞复现
  • 随机森林的特征 是放回抽样么_机器学习军火库 | 浪漫算法 随机森林
  • java空字符_Java学习之路008天
  • py怎么运行_Mac Tensorflow Faster R-CNN CPU实现环境配置及Demo运行
  • 一个数等于两个不同素数的乘机_【朝夕的ACM笔记】数论-反素数
  • spring是什么_Spring 源码第三弹!EntityResolver 是个什么鬼?
  • python界面开发webview_Python使用Pyqt5实现简易浏览器!非常实用!
  • 程序实例python_Python花式编程案例集锦(5)
  • python装饰器作用和功能_Python装饰器实现类Java注解功能
  • 树莓派无屏幕安装kali_树莓派制作魔镜屏幕旋转不正确的处理方法
  • 没有与参数列表匹配的重载函数_C++覆盖和重载的区别
  • 《网管员必读——网络组建》(第2版)电子课件下载
  • ➹使用webpack配置多页面应用(MPA)
  • 5分钟即可掌握的前端高效利器:JavaScript 策略模式
  • CAP理论的例子讲解
  • go append函数以及写入
  • JavaScript服务器推送技术之 WebSocket
  • Mybatis初体验
  • MySQL的数据类型
  • node和express搭建代理服务器(源码)
  • Quartz初级教程
  • sessionStorage和localStorage
  • Vue--数据传输
  • weex踩坑之旅第一弹 ~ 搭建具有入口文件的weex脚手架
  • zookeeper系列(七)实战分布式命名服务
  • 分布式任务队列Celery
  • 离散点最小(凸)包围边界查找
  • 前端每日实战:61# 视频演示如何用纯 CSS 创作一只咖啡壶
  • 深入浅出Node.js
  • 王永庆:技术创新改变教育未来
  • 鱼骨图 - 如何绘制?
  • 最近的计划
  • d²y/dx²; 偏导数问题 请问f1 f2是什么意思
  • 京东物流联手山西图灵打造智能供应链,让阅读更有趣 ...
  • ###51单片机学习(2)-----如何通过C语言运用延时函数设计LED流水灯
  • (2020)Java后端开发----(面试题和笔试题)
  • (C语言版)链表(三)——实现双向链表创建、删除、插入、释放内存等简单操作...
  • (react踩过的坑)antd 如何同时获取一个select 的value和 label值
  • (Redis使用系列) Springboot 使用redis实现接口幂等性拦截 十一
  • (初研) Sentence-embedding fine-tune notebook
  • (多级缓存)缓存同步
  • (牛客腾讯思维编程题)编码编码分组打印下标题目分析
  • (收藏)Git和Repo扫盲——如何取得Android源代码
  • (一)UDP基本编程步骤
  • (译) 理解 Elixir 中的宏 Macro, 第四部分:深入化
  • (转)JVM内存分配 -Xms128m -Xmx512m -XX:PermSize=128m -XX:MaxPermSize=512m
  • ./include/caffe/util/cudnn.hpp: In function ‘const char* cudnnGetErrorString(cudnnStatus_t)’: ./incl
  • .NET Framework Client Profile - a Subset of the .NET Framework Redistribution
  • .NET 依赖注入和配置系统
  • .NETCORE 开发登录接口MFA谷歌多因子身份验证
  • .NET国产化改造探索(三)、银河麒麟安装.NET 8环境