SpringCache使用详解

SpringCache

      • 1.新建测试项目SpringCache
      • 2.SpringCache整合redis
        • 2.1.@Cacheable
        • 2.2.@CacheEvict
        • 2.3.@Cacheput
        • 2.4.@Caching
        • 2.5.@CacheConfig
      • 3.SpringCache问题
      • 4.SpringCache实现多级缓存

1.新建测试项目SpringCache

引入依赖

<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><!--Mysql数据库驱动--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><!-- MyBatis--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.4.0</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency>
</dependencies>

实体类

@Data
public class User {private Long id;private String name;private Integer age;}

mapper

@Mapper
public interface UserMapper extends BaseMapper<User> {}

application.yml

spring:datasource:url: jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghaiusername: rootpassword: 123456driver-class-name: com.mysql.cj.jdbc.Driver
mybatis-plus:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

测试下没问题就搭建完成,开始springcache的测试

2.SpringCache整合redis

spring cache官方文档
spEl语法说明官方文档

下面是以redis为例,其他缓存也是下面这些步骤,一般来说要把cache抽出成一个类,下面为了测试方便直接在controller里做

1.引入依赖

<!-- redis -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

2.配置类

@EnableCaching //开启缓存
@Configuration
public class CacheConfig {@Beanpublic CacheManager redisCacheManager(RedisConnectionFactory factory) {// 配置序列化(解决乱码的问题),过期时间600秒RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()//过期时间.entryTtl(Duration.ofSeconds(600))//缓存key.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))//缓存组件value.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()))//value不为空,为空报错.disableCachingNullValues().computePrefixWith(cacheName -> cacheName + ":");RedisCacheManager cacheManager = RedisCacheManager.builder(factory).cacheDefaults(config).build();return cacheManager;}
}

3.application.yml

spring:datasource:url: jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghaiusername: rootpassword: 123456driver-class-name: com.mysql.cj.jdbc.Driverredis:host: 127.0.0.1port: 6379password: 123456
mybatis-plus:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

4.controller

@RestController
@CacheConfig(cacheNames = "user", cacheManager = "redisCacheManager")
public class UserController {@AutowiredUserMapper userMapper;@GetMapping("/list")@Cacheable(key = "#root.method.name")public List<User> list() {return userMapper.selectList(null);}
}

5.访问http://localhost:8080/list测试,数据被缓存到redis中了

2.1.@Cacheable

@Cacheable:触发缓存填充。

注解属性

注解属性作用
value / cacheNames用于指定缓存的名称,可以指定一个或多个缓存名称
key用于指定缓存的键,可以使用 SpEL 表达式
condition用于指定一个条件,如果条件成立,则执行缓存
unless用于指定一个条件,如果条件不成立,则执行缓存
keyGenerator用于指定自定义的缓存键生成器
cacheManager用于指定自定义的缓存管理器
sync用于指定是否使用同步模式,当设置为 true 时,表示在方法执行时,阻塞其他请求,直到缓存更新完成

SpEL上下文数据

属性名称描述示例
methodName正在调用的方法的名称#root.methodName
method正在调用的方法#root.method.name
target正在调用的目标对象#root.target
targetClass被调用目标的class#root.targetClass
args用于调用目标的参数#root.args[0]
caches当前被调用的方法使用的Cache#root.caches[0].name
result方法调用的结果#result
/*** 生成的缓存:myCache:qwer  value:"9999"* condition = "#param.length() > 3" 参数长度大于3进行缓存* unless = "#result == null"        结果等于null不进行缓存*/
@GetMapping("/getCachedValue")
@Cacheable(value = "myCache", key = "#param", condition = "#param.length() > 3", unless = "#result == null")
public String getCachedValue(@RequestParam("param") String param) {return "9999";
}

访问:http://localhost:8080/getCachedValue?param=qwer测试,成功缓存,修改代码return null;再测试,就不会进行缓存

/*** 可以缓存null值,但会乱码,不影响使用* 缓存null值有两种情况:* 1.return null;* 2.方法返回值为void*/
@GetMapping("/getUser")
@Cacheable(key = "#uid")
public User getUser(@RequestParam("uid") Long uid) {return userMapper.selectById(uid);
}

在这里插入图片描述

2.2.@CacheEvict

@CacheEvict:触发缓存逐出。

@GetMapping("/cacheEvict")
@CacheEvict(key = "'list'")//清除键为key的缓存
public void cacheEvict(){
}@GetMapping("/cacheEvictAll")
@CacheEvict(key = "'user'", allEntries = true)//清除user分区下的所有缓存
public void cacheEvictAll() {
}
2.3.@Cacheput

@CachePut:在不干扰方法执行的情况下更新缓存。

@GetMapping("/getUser")
@Cacheable(key = "#uid")
public User getUser(@RequestParam("uid") Long uid) {return userMapper.selectById(uid);
}@GetMapping("/update")
@CachePut(key = "#uid")
public User update(@RequestParam("uid") Long uid) {User user = new User();user.setId(uid);user.setName("lisi9999");userMapper.updateById(user);return user;
}

1.先http://localhost:8080/getUser?uid=2进行缓存
2.再http://localhost:8080/update?uid=2刷新缓存
3.再http://localhost:8080/getUser?uid=2查缓存
可以看到缓存被正确更新

注意:update方法返回值不能写void,否则会触发缓存空值的情况,缓存被刷新成乱码了

2.4.@Caching

@Caching:重新组合要应用于方法的多个缓存操作。

/*** @Cacheable(key = "'allBooks'"):表示方法的返回值应该被缓存,使用 allBooks 作为缓存的键。* @CacheEvict(key = "#isbn"):表示在调用这个方法时,会清除缓存中键为 #isbn 的缓存项。* @CacheEvict(key = "'popularBooks'"):表示在调用这个方法时,会清除缓存中键为 'popularBooks' 的缓存项。*/
@Caching(cacheable = @Cacheable(key = "'allBooks'"),evict = {@CacheEvict(key = "#isbn"),@CacheEvict(key = "'popularBooks'")}
)
public String updateBookByIsbn(String isbn, String newTitle) {System.out.println("Updating book in the database for ISBN: " + isbn);// Simulate updating data in a databasereturn newTitle;
}
2.5.@CacheConfig

@CacheConfig:在类级别共享一些常见的缓存相关设置。

@CacheConfig(cacheNames = "user", cacheManager = "redisCacheManager")
public class UserCache {}

3.SpringCache问题

springCache的这些注解也受@Transactional的事务控制

@Transactional
@Cacheable(value = "myCache", key = "#id")
public String getCachedValueById(long id) {// 查询底层数据源,如果缓存中没有数据return fetchDataFromDataSource(id);
}

@Cacheable 注解被用于方法 getCachedValueById 上,而该方法也被 @Transactional 注解标记。这意味着当方法被调用时,缓存的操作和底层数据源的查询将在同一个事务中进行。如果事务回滚(例如,由于异常的发生),缓存的操作也会被回滚,确保数据的一致性。

springcache的读模式和写模式什么意思,为什么说springcache解决了读模式的缓存击穿,缓存穿透,缓存雪崩问题,没有解决写模式的这些问题

读模式和写模式是缓存中常用的两种操作方式,分别涉及到对缓存的读取和写入。

  1. 读模式(Read-Through)
    读模式是指在读取数据时,首先尝试从缓存中获取数据。如果缓存中存在数据,则直接返回缓存的值,避免了对底层数据源(例如数据库)的直接访问。如果缓存中不存在数据,系统会查询底层数据源,将查询到的数据加载到缓存中,并返回给调用方。

Spring Cache 中的 @Cacheable 注解是典型的读模式的代表。这样的模式可以有效减轻对底层数据源的访问压力,提高系统性能。

  1. 写模式(Write-Through)
    写模式是指在对数据进行写入或修改时,首先对底层数据源进行相应的操作,然后再更新或清空缓存。这样确保了缓存和底层数据源的一致性。

Spring Cache 中的 @CachePut 和 @CacheEvict 注解是写模式的代表。@CachePut 用于更新缓存,@CacheEvict 用于清除缓存。

关于 Spring Cache 解决问题的说法

关于 Spring Cache 解决了读模式的缓存击穿、缓存穿透、缓存雪崩问题的说法,主要是因为 Spring Cache 提供了对这些问题的解决方案:

  • 缓存击穿: 通过 @Cacheable 注解的 sync 属性,可以控制是否使用同步模式,以避免在高并发情况下多个线程同时查询缓存失效的情况。

  • 缓存穿透: 通过 @Cacheable 注解的 cache-null-values 属性,可以缓存空值,防止对于一些不存在的 key,频繁查询底层数据源。

  • 缓存雪崩: 通过设置缓存项的过期时间,以及使用随机时间避免同时失效大量缓存项,可以减缓缓存雪崩问题的发生。

然而,写模式中可能存在一些问题,比如缓存和底层数据源的一致性问题,因为在更新底层数据源和更新缓存之间存在一定的时间差。Spring Cache 没有提供对写模式问题的直接解决方案。在一些对数据一致性要求较高的场景中,可能需要结合其他手段(如数据库事务、消息队列等)来保证写操作的一致性。

4.SpringCache实现多级缓存

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

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

相关文章

内裤洗衣机有用吗?口碑最好的小型洗衣机

想必各位小伙伴都知道我们的贴身衣物&#xff0c;不可以与其他衣服一起在洗衣机中清洗&#xff0c;每次都需要把内衣裤挑选出来手洗&#xff0c;但是我们每天都要上厕所&#xff0c;难免会沾上污渍和细菌&#xff0c;我们在用手搓洗的过程中很难把细菌给清除掉&#xff0c;所以…

ios打包,证书获取

HBuilderX 打包ios界面&#xff1a; Bundle ID(AppID)&#xff1a; 又称应用ID&#xff0c;是每一个ios应用的唯一标识&#xff0c;就像一个人的身份证号码&#xff1b; 每开发一个新应用&#xff0c;首先都需要先去创建一个Bundle ID Bundle ID 格式&#xff1a; 一般为&…

用Python写了一个贪吃蛇大冒险小游戏

一、游戏简介 1.1 游戏操作及游戏规则 &#xff08;1&#xff09;游戏开始后&#xff0c;通过键盘上下左右键控制贪吃蛇移动寻找食物&#xff1b; &#xff08;2&#xff09;贪吃蛇每吃一个食物&#xff0c;身长会增加一个单位&#xff1b; &#xff08;3&#xff09;在正常模…

【HarmonyOS】 低代码平台组件拖拽使用技巧之登录组件

【关键字】 HarmonyOS、低代码平台、组件拖拽、登录组件、代码编辑器 1、写在前面 前面我们介绍了低代码中堆叠容器、滚动容器、网格布局、页签容器以及一些常用容器和组件的拖拽使用方法&#xff0c;本篇我们来介绍一个新的组件&#xff0c;这个组件是属于业务组件——登录组…

Modbus转Profinet网关:PLC与天信流量计通讯的经典案例

无论您是PLC或工业设备的制造商&#xff0c;还是工业自动化系统的维护人员&#xff0c;可能会遇到需要将不同协议的设备连接组合并通讯的情况&#xff0c;Modbus和Profinet是现代工业自动化中常见的两种通信协议&#xff0c;在工业控制领域中被广泛应用。 在这种情况绝大多数会…

快速上手Banana Pi BPI-M4 Zero 全志科技H618开源硬件开发开发板

Linux[编辑] 准备[编辑] 1. Linux镜像支持SD卡或EMMC启动&#xff0c;并且会优先从SD卡启动。 2. 建议使用A1级卡&#xff0c;至少8GB。 3. 如果您想从 SD 卡启动&#xff0c;请确保可启动 EMMC 已格式化。 4. 如果您想从 EMMC 启动并使用 Sdcard 作为存储&#xff0c;请确…

《微信小程序开发从入门到实战》学习二十六

3.4 开发参与投票页面 参与投票页面同样需要收集用户提交的信息&#xff0c;哪个用户在哪个投票选择了什么选项&#xff0c;因此它也是一个表单页面 3.4.1 如何获取投票信息 假设用户A在投票创建页面后填了表单&#xff08;1.创建投票&#xff09;&#xff0c;用户A 点了提交…

山西电力市场日前价格预测【2023-11-24】

日前价格预测 预测说明&#xff1a; 如上图所示&#xff0c;预测明日&#xff08;2023-11-24&#xff09;山西电力市场全天平均日前电价为415.13元/MWh。其中&#xff0c;最高日前电价为685.26元/MWh&#xff0c;预计出现在18:00。最低日前电价为296.84元/MWh&#xff0c;预计…

Web实战:基于Django与Bootstrap的在线计算器

文章目录 写在前面实验目标实验内容1. 创建项目2. 导入框架3. 配置项目前端代码后端代码 4. 运行项目 注意事项写在后面 写在前面 本期内容&#xff1a;基于Django与Bootstrap的在线计算器 实验环境&#xff1a; vscodepython(3.11.4)django(4.2.7)bootstrap(3.4.1)jquery(3…

美国DDoS服务器:如何保护你的网站免遭攻击?

​  在当今数字化时代&#xff0c;互联网已经成为人们生活中不可或缺的一部分。随着互联网的普及和发展&#xff0c;网络安全问题也日益严重。其中&#xff0c;DDoS攻击是目前最常见和具有破坏性的网络攻击之一。那么&#xff0c;如何保护你的网站免遭DDoS攻击呢?下面将介绍…

C#开发的OpenRA游戏之属性Selectable(9)

C#开发的OpenRA游戏之属性Selectable(9) 在游戏里,一个物品是否具有选中的能力,是通过添加属性Selectable来实现的。当一个物品不能被用户选取,那么就不要添加这个属性。 这个属性定义在下面这段描述里: ^Selectable: Selectable: SelectionDecorations: WithSpriteCon…

CSS画一条线

<p style"border: 1px solid rgba(0, 0, 0, 0.1);"></p> 效果&#xff1a;

MATLAB中imbothat函数用法

目录 语法 说明 示例 使用底帽和顶帽滤波增强对比度 imbothat函数的功能是对图像进行底帽滤波。 语法 J imbothat(I,SE) J imbothat(I,nhood) 说明 J imbothat(I,SE) 使用结构元素 SE 对灰度或二值图像 I 执行形态学底帽滤波。底帽滤波计算图像的形态学闭运算&#…

苹果手机内存满了怎么清理?这里有你想要的答案!

手机内存不足是一个比较普遍的现象。由于现在手机应用程序的功能越来越强大&#xff0c;所以占用的内存也越来越大。同时用户会在手机中存储大量的数据&#xff0c;如照片、视频、文档等&#xff0c;这些都会占用大量的手机空间。那么&#xff0c;苹果手机内存满了怎么清理&…

C++数组中重复的数字

3. 数组中重复的数字 题目链接 牛客网 题目描述 在一个长度为 n 的数组里的所有数字都在 0 到 n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字是重复的,也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 Input: {2, 3, 1, 0, 2, 5}Output: 2解题…

Altium Designer学习笔记10

再次根据图纸进行布局走线&#xff1a; 这个MT2492 建议的布局走线。 那我这边应该是尽量按照该图进行布局&#xff1a; 其中我看到C1的电容的封装使用的是电感的封装&#xff0c;需要进行更换处理&#xff1a; 执行Validate Changes和Execute Changes操作&#xff0c;更新&a…

程序员最奔溃的瞬间

身为程序员哪一个瞬间让你最奔溃&#xff1f; *程序员最奔溃的瞬间&#xff0c; 勇士&#xff1f; or 无知&#xff1f;

Element中el-table组件右侧空白隐藏-滚动条

开发情况&#xff1a; 固定table高度时&#xff0c;出现滚动条&#xff0c;我们希望隐藏滚动条&#xff0c;或修改滚动条样式&#xff0c;出现table右边出现15px 的固定留白。 代码示例 <el-table class"controlTable" header-row-class-name"controlHead…

C语言二十一弹 --打印空心正方形

C语言实现打印空心正方形 思路&#xff1a;观察图中空心正方形&#xff0c;可知首行列和尾行列被黑色外框包裹&#xff0c;其它均为空。所以按观察打印即可。 总代码 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h>int main() {int n 0;while (scanf("%d&q…

关于数据摆渡 你关心的5个问题都在这儿!

数据摆渡&#xff0c;这个词语的概念源自于网络隔离和数据交换的场景和需求。不管是物理隔离、协议隔离、应用隔离还是逻辑隔离&#xff0c;最终目的都是为了保护内部核心数据的安全。而隔离之后&#xff0c;又必然会存在文件交换的需求。 传统的跨网数据摆渡方式经历了从人工U…