SpringCache 缓存 - @Cacheable、@CacheEvict、@CachePut、@Caching、CacheConfig 以及优劣分析

 

目录

SpringCache 缓存

环境配置

1)依赖如下

2)配置文件

3)设置缓存的 value 序列化为 JSON 格式

4)@EnableCaching 

实战开发

@Cacheable

@CacheEvict

@CachePut

@Caching

@CacheConfig

SpringCache 的优势和劣势

读操作(优势)

写操作(劣势)

总结


SpringCache 缓存


环境配置

1)依赖如下

父依赖 SpringBoot 3.2.5

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

2)配置文件

spring:cache:type: redisredis:time-to-live: 3600000# key-prefix: CACHE_use-key-prefix: true cache-null-values: true
  • time-to-live: 3600000 -> 缓存过期时间,单位毫秒,此处相当于 1 小时(实际上也就解决了雪崩问题,因为一般设置每一个缓存时的时间线不一样)
  • key-prefix: CACHE_ -> 缓存 key 前缀(一般不用这个属性,而是使用分区名作为 key 前缀)
  • use-key-prefix: true -> 是否使用缓存分区名作为 key 前缀(分区名在 @Cacheable 中指定),建议为 true
  • cache-null-values: true -> 是否缓存空值(解决缓存穿透问题),建议为 true

3)设置缓存的 value 序列化为 JSON 格式

import org.springframework.boot.autoconfigure.cache.CacheProperties
import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.cache.annotation.EnableCaching
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.data.redis.cache.RedisCacheConfiguration
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer
import org.springframework.data.redis.serializer.RedisSerializationContext
import org.springframework.data.redis.serializer.StringRedisSerializer@Configuration
@EnableConfigurationProperties(CacheProperties::class) //让配置文件中的配置生效
@EnableCaching // 开启 SpringCache 缓存功能(如果这里不写这个注解,启动类上也一定要有!!!)
class MyCacheConfig {@Beanfun redisCacheConfiguration(cacheProperties: CacheProperties): RedisCacheConfiguration {//这里源码怎么写,咱们咱们写(只需要改一下缓存 value 的序列化方式即可)var config = RedisCacheConfiguration.defaultCacheConfig()//设置 key value 的序列化方式config = config.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(StringRedisSerializer()))config = config.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(GenericJackson2JsonRedisSerializer()))val redisProperties = cacheProperties.redis//将配置文件中的所有配置都生效redisProperties.timeToLive?.let {config = config.entryTtl(it)}redisProperties.keyPrefix?.let {config = config.prefixCacheNameWith(it)}if (!redisProperties.isCacheNullValues) {config = config.disableCachingNullValues()}if (!redisProperties.isUseKeyPrefix) {config = config.disableKeyPrefix()}return config}}

4)@EnableCaching 

@EnableCaching 表示开启 SpringCache 缓存功能,加在 启动类 或者 配置类 上都可以.

实战开发

@Cacheable

a)使用说明:

@Cacheable 用来将方法的返回值数据保存到缓存中.

常用属性如下:

  • value:表示将当前缓存数据放到哪个 缓存组 中(可以理解为放到哪个文件夹下). 
    • 例如 @Cacheable(value = ["user"])
  • key:指定 key 是什么.  接受一个 SpEL 表达式,例如如下表格中的示例
    • 例如方法名作为 key:@Cacheable(value = ["user"], key = "#root.method.name")
    • 另外,如果不想使用 SpEL 表达式,可以直接在双引号内加上一对单引号,例如 key 为 "userinfo":@Cacheable(value = ["user"], key = "'userinfo'")
  • condition:条件判断属性,只有符合条件才可以被缓存.
    • 例如方法参数中的 id > 0 返回值才能被缓存 @Cacheable(value = ["user"], key = "#root.method.name", condition = "#id > 0")
  • sync:是否为同步执行. 如果设置为 true,会加锁(本地锁),可以用来解决击穿问题.

b)案例如下:

例如通过 SpEL表达式设置 缓存的 key 为 动态的id + "userinfo" ,

    @Cacheable(value = ["user"], key = "#id + 'userinfo'")override fun getUserinfo(id: Long): UserinfoVo {//业务逻辑...println("查询数据库...")return UserinfoVo( // 这里的 UserinfoVo 必须要有无参构造才行,否则缓存将来读取的时候会报错id = id,name = "cyk",age = 21,)}

第一查询之后,就可以看到 Redis 上面已经存在该数据.  之后的只要缓存未过期,都会直接查缓存.

@CacheEvict

a)使用说明

@CacheEvict 用来将数据从缓存中删除. 

他常常被用来实现 “失效模式” 来解决缓存一致性问题(数据库中的数据被更新之后,直接删除缓存上的数据即可,下次查询的时候,自动同步到缓存上).

常用属性和 @Cacheable 差不多,这里不再赘述.

b)案例如下

例如实现缓存失效:现在要进行用户信息的修改,那么为了保证缓存和数据库中数据一致,修改完数据库之后的就直接删除对应的缓存数据即可~  下次查询时,再更新缓存.

这里通过 SpEL 表达式设置要删除的缓存的 key 为 动态的id + "userinfo" ,

    /***  通过 @CacheEvict 实现缓存失效,下次查询时,再更新缓存*/@CacheEvict(value = ["user"], key = "#dto.id + 'userinfo'")override fun updateUserinfo(dto: UserinfoDto) {//业务逻辑...println("修改数据库数据...")}

另外,还可以通过 属性,删除同一个分区下的所有缓存(慎用)

@CacheEvict(value = ["user"],  allEntries = true)

@CachePut

a)使用说明

@CachePut 用来更新缓存数据. 

与 @Cacheable 不同的是,使用 @CachePut 标注的方法在执行前不会检查缓存中是否存在这个数据,而是每次都会执行这个方法,并将返回值写入到缓存中.

属性上和 @Cacheable 是一样的,这里不再赘述.

b)案例如下

    @CachePut(value = ["user"], key = "#dto.id + 'userinfo'")override fun putUserinfo(dto: UserinfoDto): UserinfoVo {//业务逻辑println("更新数据库...")return with(dto) {UserinfoVo(id = id,name = name,age = age,)}}

@Caching

@Caching 用来组合以上多个操作.

例如删除同时删除多个缓存数据

    @Caching(evict = [CacheEvict(value = ["user"], key = "#dto.id + 'userinfo'"),CacheEvict(value = ["user"], key = "#dto.id + 1 + 'userinfo'"),])override fun updateUserinfo(dto: UserinfoDto) {//业务逻辑...println("修改数据库数据...")}

@CacheConfig

如果一个类中有很多一样的 cacheName、keyGenerator、cacheManager、cacheResolver,可以直接使用 @CacheConfig 在类上声明,那么这个类中的所有标记了 Cache 相关注解的方法都会共享 @CacheConfig 属性

@Service
//@CacheConfig(cacheNames = ["aaa", "bbb"]) 会创建两个缓存分区, aaa 和 bbb
@CacheConfig(cacheNames = ["user"])
class CacheServiceImpl: CacheService {@Cacheable(key = "#id + 'userinfo'")override fun getUserinfo(id: Long): UserinfoVo {//业务逻辑...println("查询数据库...")return UserinfoVo( // 这里的 UserinfoVo 必须要有无参构造才行,否则缓存将来读取的时候会报错id = id,name = "cyk",age = 21,)}/***  通过 @CacheEvict 实现缓存失效,下次查询时,再更新缓存*/@CacheEvict(key = "#dto.id + 'userinfo'")override fun updateUserinfo(dto: UserinfoDto) {//业务逻辑...println("修改数据库数据...")}@CachePut(key = "#dto.id + 'userinfo'")override fun putUserinfo(dto: UserinfoDto): UserinfoVo {//业务逻辑println("更新数据库...")return with(dto) {UserinfoVo(id = id,name = name,age = age,)}}}

SpringCache 的优势和劣势

读操作(优势)

SpringCache 在读操作上的处理的还是很到位的:

  • 缓存穿透:配置文件中设置 cache-null-values: true,这样就会将查询为 null 也缓存起来.
  • 缓存击穿:配置文件中设置 sync=true,这样就可以对方法进行加锁,解决击穿问题.
  • 缓存雪崩:配置文件中设置 time-to-live=3600000 用来设置过期时间(虽然设置的时间是统一的,但是一般情况下情况下触发的时机是不同的,也就相当于是有了随机因子).

写操作(劣势)

  • 对于读写并发高,或者写并发高的场景不太好应对.
  • 针对于一些特殊的写场景,还是要定制化一下的

总结

对于读多写少,一致性要求不高的数据,完全可以使用 SpringCache 来简化开发(只要缓存的数据有过期时间就可以).

对于一致性要求高的场景,也没必要引入引入缓存,直接对数据库进行读写即可.

特殊数据特殊处理.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/348042.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ADS基础教程19 - 电磁仿真(EM)基本概念和实操

EM介绍 一、引言二、基本概念1.EM介绍2.Momentum介绍3.FEM介绍4.Substrate介绍 三、创建Layout并进行Momentum仿真1.创建Layout2.添加Microtrip&#xff08;微带线&#xff09;3.添加Substrate4.Momentum仿真 四、总结 一、引言 本章节开始介绍EM的基本概念、内容以及实现具体…

反向传播算法

在深度学习和神经网络中&#xff0c;反向传播算法是一种至关重要的技术&#xff0c;它使得网络能够通过学习不断调整自身的参数以优化性能。作为训练神经网络的核心机制&#xff0c;反向传播通过计算损失函数对模型参数的梯度&#xff0c;并据此更新网络权重&#xff0c;从而逐…

this关键字,构造函数(构造器)

文章目录 thisthis是什么应用场景 构造器注意事项代码演示 this this是什么 this就是一个变量&#xff0c;可以在方法中&#xff0c;拿到当前对象 应用场景 解决变量名称 冲突问题 构造器 注意事项 必须和类名相同没有返回值只要参数不同&#xff08;个数不同&#xff0…

ISO 26262《道路车辆功能安全》

ISO 26262是关于道路车辆功能安全的国际标准&#xff0c;专门针对总重不超过3.5吨的八座乘用车及其安全相关电子电气系统&#xff08;E/E系统&#xff09;的功能安全而制定。以下是关于ISO 26262的详细解释&#xff1a; 一、背景与目的 ISO 26262是在2011年11月15日正式发布的…

Java基础面试重点-2

21. JVM是如何处理异常&#xff08;大概流程&#xff09;&#xff1f; 如果发生异常&#xff0c;方法会创建一个异常对象&#xff08;包括&#xff1a;异常名称、异常描述以及异常发生时应用程序的状态&#xff09;&#xff0c;并转交给JVM。创建异常对象&#xff0c;并转交给…

UML相关1

汽车租赁系统中的用例图简述(10分) 本系统根据功能可以分为三个用例图&#xff1a; 客户用例图&#xff1a;主要描述客户注册、登录、找回密码、查询车辆信息&#xff08;包括所有车辆信息、已借车辆信息、租赁历史信息&#xff09;、修改个人信息、网上预订车辆、电话预定车…

LabVIEW结构体内部缺陷振动检测

结构体内部缺陷会改变其振动特性&#xff0c;通过振动分析可以检测并定位这些缺陷。本文详细分析内部缺陷对振动的影响&#xff0c;从频谱分析、时域分析和模态分析等多角度探讨基于LabVIEW的检测方法&#xff0c;提供实施步骤和注意事项&#xff0c;帮助工程师有效利用LabVIEW…

Windows下Qt5.14.2连接华为IoTDA平台

一、华为IoTDA简介 华为云物联网平台&#xff08;IoT 设备接入云服务&#xff09;提供海量设备的接入和管理能力&#xff0c;将物理设备联接到云&#xff0c;支撑设备数据采集上云和云端下发命令给设备进行远程控制&#xff0c;配合华为云其他产品&#xff0c;帮助您快速构筑物…

JAVA:在IDEA引入本地jar包的方法并解决打包scope为system时发布无法打包进lib的方案

一.引入本地Jar包的步骤 有时maven依耐的包是本地的jar包&#xff0c;此时需要进行以下步骤设置。 步骤1.在pom.xml中添加插件设置,将system范围包含进来&#xff0c;此设置是为了在打包时&#xff0c;本地jar包自动生成到部署包里。(若无法打进包&#xff0c;请参考下文的方…

面向对象三大特征之:封装

文章目录 什么是封装&#xff1f;封装的设计规范 什么是封装&#xff1f; 就是用类设计对象处理某一个事物的数据时&#xff0c;应该把要处理的数据&#xff0c;以及处理这些书记的方法设计到一个对象中去。 封装的设计规范 合理隐藏&#xff0c;合理暴露 public就是都能访问…

【Python】解决Python报错:ValueError: not enough values to unpack (expected 2, got 1)

​​​​ 文章目录 引言1. 错误详解2. 常见的出错场景2.1 函数返回值解包2.2 遍历含有不同长度元组的列表 3. 解决方案3.1 检查和调整返回值3.2 安全的解包操作 4. 预防措施4.1 使用异常处理4.2 单元测试 结语 引言 在Python编程中&#xff0c;ValueError 是一个常见的异常类…

服务器配置(初始化)

一&#xff1a;什么是云服务器及用途&#xff1a; 云服务器(Elastic Compute Service, ECS)是一种简单高效、安全可靠、处理能力可弹性伸缩的计算服务。其管理方式比物理服务器更简单高效。用户无需提前购买硬件&#xff0c;即可迅速创建或释放任意多台云服务器。 我个人感觉就…

录取查询小程序怎么制作?

招生老师往往需要花费大量的时间和精力去手动整理学生的录取信息&#xff0c;并一一通知学生。那时的录取查询系统&#xff0c;复杂而繁琐&#xff0c;要处理大量的数据&#xff0c;还要确保信息的准确无误和安全。经常为了发布录取结果&#xff0c;不得不加班到深夜&#xff0…

[学习笔记] VFX Silhouette

目录 Part 1 : The interface of Silhouettte &#xff08;Silhouette的界面介绍&#xff09; Part 2: The shape divisions and manual roto&#xff08;形状分区和手动roto工作&#xff09;: Part 3: tracking &#xff1a; Part 4: Mocha Tracking Part 5: Motion Blur(…

SQL 截取函数

目录 1、substring 2、left 3、right 4、substring_index 1、substring 用途&#xff1a;字段截取从指定开始的字符开始&#xff0c;截取要的数&#xff1b;指定开始的字符数字可以用负的&#xff0c;指定开始的字符从后往前(向左)数&#xff0c;截取要的数不能为负。 语…

mysql知识点

目录 1、数据库定义语言&#xff08;DDL&#xff09;&#xff08;1&#xff09;创建数据库&#xff08;2&#xff09;创建表SQL数据类型列级约束条件表级约束条件&#xff08;3&#xff09;修改表 2、数据库操纵语言&#xff08;DML&#xff09;&#xff08;1&#xff09;插入数…

【STM32】输入捕获应用-测量脉宽或者频率(方法1)

图1 脉宽/频率测量示意图 1 测量频率 当捕获通道TIx 上出现上升沿时&#xff0c;发生第一次捕获&#xff0c;计数器CNT 的值会被锁存到捕获寄存器CCR中&#xff0c;而且还会进入捕获中断&#xff0c;在中断服务程序中记录一次捕获&#xff08;可以用一个标志变量来记录&#…

Linux “ 软件管理 “

软件管理 widows 安装 方法一&#xff1a; 双击exe安装包&#xff0c;就可以安装。 用exe安装的软件会破记录到注册表中。 注册会记录安装位置&#xff0c;软件名称。 方法二&#xff1a; 用绿色方式进行安装。 不用写到注册表中&#xff0c;因此无法在开始菜单里面查看和卸…

【Java】解决Java报错:IllegalArgumentException

文章目录 引言1. 错误详解2. 常见的出错场景2.1 非法的参数值2.2 空值或 null 参数2.3 非法的数组索引 3. 解决方案3.1 参数验证3.2 使用自定义异常3.3 使用Java标准库中的 Objects 类 4. 预防措施4.1 编写防御性代码4.2 使用注解和检查工具4.3 单元测试 结语 引言 在Java编程…

LM2576系列3A开关型DCDC BUCK降压稳压器

前言&#xff1a; 老款DCDC&#xff0c;使用历史几十年了&#xff0c;今天设计仍然使用这个DCDC的&#xff0c;是不合适的。主要缺点是开关频率较低只有几十Khz&#xff0c;导致需要使用较大感量的功率电感&#xff0c;这样的电感价格较高&#xff0c;且占用PCB空间较大&#…