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

Redis--缓存工具封装

经过前面的学习,发现缓存中的问题,无论是缓存穿透,缓存雪崩,还是缓存击穿,这些问题的解决方案业务代码逻辑都很复杂,我们也不应该每次都来重写这些逻辑,我们可以将其封装成工具。而在封装的时候,也会有不少的问题需要去解决。

案例学习:缓存工具封装

基于StringRedisTemplate封装一个缓存工具类,满足下列需求:

  • 方法一:将任意Java对象序列化成JSON并存储在String类型的key中,并且可以设置TTL过期时间

  • 方法二:将任意Java对象序列化成JSON并存储在String类型的key中,并且可以设置逻辑过期时间,用于处理缓存击穿问题

  • 方法三:根据指定的key查询缓存,并且反序列化成指定类型,利用缓存空值的方式解决缓存穿透问题

  • 方法四:根据指定的key查询缓存,并且反序列化成指定类型,需要利用逻辑过期解决缓存击穿问题

代码展示:

首先需要先声明是一个组件@Component,方便spring管理,再添加一个@slf4j注解方便日志输出,管理等,再注入StringRedisTemplate的Bean对象,使用构造器方式注入

 @Slf4j@Componentpublic class CacheClient {//  注入redisTemplate,用构造器模式注入private final StringRedisTemplate  stringRedisTemplate;​public CacheClient(StringRedisTemplate stringRedisTemplate) {this.stringRedisTemplate = stringRedisTemplate;}

方法一:将任意Java对象序列化成JSON并存储在String类型的key中,并且可以设置TTL过期时间

 //方法一:将任意Java对象序列化成JSON并存储在String类型的key中,并且可以设置TTL过期时间//编译set方法,需要注意的是 key是String类型,value是Object类型,所以需要转换一下,将 value 转为json字符串public void set(String key, Object value, Long time, TimeUnit unit){stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(value),time,unit);}

方法二:将任意Java对象序列化成JSON并存储在String类型的key中,并且可以设置逻辑过期时间,用于处理缓存击穿问题

 //方法二:- 将任意Java对象序列化成JSON并存储在String类型的key中,并且可以设置逻辑过期时间,用于处理缓存击穿问题public void setWithLogicalExpire(String key, Object value, Long time, TimeUnit unit){//逻辑过期的核心思想,时将过期时间作为字段写入到数据中, 读取的时候,先判断是否过期,如果过期,则返回null,否则返回数据//设置逻辑过期RedisData redisData = new RedisData();redisData.setData(value);redisData.setExpireTime(LocalDateTime.now().plusSeconds(unit.toSeconds(time)));stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(redisData));}

方法三:根据指定的key查询缓存,并且反序列化成指定类型,利用缓存空值的方式解决缓存穿透问题

 //方法三:根据指定的key查询缓存,并且反序列化成指定类型,利用缓存控制的方式解决缓存穿透问题//设置返回值为泛型,因为在编译工具类,返回值无法确定,需要调用者告知。//  参数:keyPrefix key前缀,id 商铺id,type 返回值类型//id类型也不确定,需要使用泛型public  <R,ID> R queryWithPassThrough(String KeyPrefix, ID id, Class<R> type, Function<ID,R> dbFallback,Long time,TimeUnit unit) {//1.从redis中查询商铺缓存String json = stringRedisTemplate.opsForValue().get(CACHE_SHOP_KEY + id);// 2.判断是否存在if (StrUtil.isNotBlank(json)) {//  3.存在,做反序列化,返回return  JSONUtil.toBean(json, type);}//判断命中的是否是空值if (json!= null) {return null;}//  4.不存在,根据id查询数据库 我们工具类不清楚实体类以及数据库方法,所以我们需要让调用者将这段逻辑提供给我们,使用函数式接口,//有参数,有返回值 ,使用函数式接口//Function<ID,R> dbFallback,ID为参数,R为返回值R r = dbFallback.apply(id);//  5.不存在,返回错误if (r == null) {//  6.不存在,写入redisstringRedisTemplate.opsForValue().set(KeyPrefix + id, "", CACHE_NULL_TTL, TimeUnit.MINUTES);//  5.不存在,返回错误return null;}//存在,写入redis//时间不能够写死,需要根据业务来定this.set(KeyPrefix + id, r, time, unit);return r;}

在这里进行测试,进入ShopServiceImpl,调用工具类,尝试替代解决缓存穿透方案的业务代码

首先注入工具类Bean对象

 @Resourceprivate CacheClient  cacheClient;

进行方法三调用

 Shop shop = cacheClient.queryWithPassThrough(CACHE_SHOP_KEY, id, Shop.class, this::getById, CACHE_SHOP_TTL, TimeUnit.MINUTES);

开始测试:

访问测试接口,观察数据库查询次数

image-20250529213718631

数据库仅查询一次。

测试成功。工具类搭建成功

方法四:根据指定的key查询缓存,并且反序列化成指定类型,需要利用逻辑过期解决缓存击穿问题

 
 private static final ExecutorService CACHE_REBUILD_EXECUTOR = Executors.newFixedThreadPool(10);//方法四:根据指定的key查询缓存,并且反序列化成指定类型,利用逻辑过期解决缓存击穿问题public <R ,ID> R queryWithLogicalExpire(String keyPrefix,ID id,Class<R> type,Function<ID,R> dbFallback,Long time,TimeUnit unit){//1.从redis中查询商铺缓存String json = stringRedisTemplate.opsForValue().get(keyPrefix+id);// 2.判断是否存在if(StrUtil.isBlank(json)) {​//  3.不存在,直接返回空return null;}​//4.命中,需要把json反序列化为对象RedisData redisData = JSONUtil.toBean(json, RedisData.class);//  4.存在,判断缓存是否过期//Data实际上是jsonObject对象R r = JSONUtil.toBean((JSONObject) redisData.getData(), type);LocalDateTime expireTime = redisData.getExpireTime();//  5.判断是否过期if(expireTime.isAfter(LocalDateTime.now())) {//  5.1.未过期,直接返回店铺信息return r;}//  6.重建缓存// 6.1.获取互斥锁String lock = LOCK_SHOP_KEY + id;boolean isLock = tryLock(lock);// 6.2.判断是否获取锁成功if(isLock) {//再次检测redis缓存是否过期redisData = JSONUtil.toBean(stringRedisTemplate.opsForValue().get(keyPrefix + id), RedisData.class);if (redisData.getExpireTime().isAfter(LocalDateTime.now())) {//  6.1.未过期,直接返回。return JSONUtil.toBean((JSONObject) redisData.getData(), type);}//  6.3.成功,开启独立线程,实现缓存重建CACHE_REBUILD_EXECUTOR.submit(() -> {try {//  重建缓存R r1 = dbFallback.apply(id);//写入RedissetWithLogicalExpire(keyPrefix+id,r1,time,unit);} catch (Exception e) {throw new RuntimeException(e);} finally {//  释放锁unlock(lock);}});}return r;}private boolean tryLock(String key){//设置有效期时间取决于业务执行时间,一般比业务时间长一些即可。Boolean flag = stringRedisTemplate.opsForValue().setIfAbsent(key, "1", 10, TimeUnit.SECONDS);//建议不要直接返回flag,防止返回空指针,因为Boolean是boolean的包装类,需要进行拆箱操作,可能导致空指针 网络问题或者键不存在但Redis未响应,可能会返回null,因此需要实用工具类判断。改成BooleanUtil.isTrue(flag)。return  BooleanUtil.isTrue(flag);}//  释放锁private void unlock(String key){stringRedisTemplate.delete(key);}

测试:

调用工具类:

 Shop shop = cacheClient.queryWithLogicalExpire(CACHE_SHOP_KEY, id, Shop.class, this::getById, CACHE_SHOP_TTL, TimeUnit.MINUTES);

注意事项:进行测试之前需要提前将数据存入Redis中,并且保证已经过期。

在测试单元中进行存储:

 @SpringBootTestclass HmDianPingApplicationTests {@Resourceprivate ShopServiceImpl shopService;@Resourceprivate CacheClient cacheClient;@Testvoid testSaveShop() throws InterruptedException {shopService.getById(1L);cacheClient.setWithLogicalExpire(CACHE_SHOP_KEY,1L,10L, TimeUnit.SECONDS);}

测试结果:

新建100个线程并发执行。

image-20250529192207335

检查成果:

image-20250529192354366

测试成功,在前一半线程中,数据为旧数据,后一半线程数据为新数据。

查看数据库查询次数,只查询一次,说明并无线程并发问题。

image-20250529213718631

代码汇总:

 @Slf4j@Componentpublic class CacheClient {//  注入redisTemplate,用构造器模式注入private final StringRedisTemplate stringRedisTemplate;​public CacheClient(StringRedisTemplate stringRedisTemplate) {this.stringRedisTemplate = stringRedisTemplate;}​//方法一:将任意Java对象序列化成JSON并存储在String类型的key中,并且可以设置TTL过期时间//编译set方法,需要注意的是 key是String类型,value是Object类型,所以需要转换一下,将 value 转为json字符串public void set(String key, Object value, Long time, TimeUnit unit) {stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(value), time, unit);}​//方法二:- 将任意Java对象序列化成JSON并存储在String类型的key中,并且可以设置逻辑过期时间,用于处理缓存击穿问题public void setWithLogicalExpire(String key, Object value, Long time, TimeUnit unit) {//逻辑过期的核心思想,时将过期时间作为字段写入到数据中, 读取的时候,先判断是否过期,如果过期,则返回null,否则返回数据//设置逻辑过期RedisData redisData = new RedisData();redisData.setData(value);redisData.setExpireTime(LocalDateTime.now().plusSeconds(unit.toSeconds(time)));stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(redisData));}​//方法三:根据指定的key查询缓存,并且反序列化成指定类型,利用缓存控制的方式解决缓存穿透问题//设置返回值为泛型,因为在编译工具类,返回值无法确定,需要调用者告知。//  参数:keyPrefix key前缀,id 商铺id,type 返回值类型//id类型也不确定,需要使用泛型public <R, ID> R queryWithPassThrough(String KeyPrefix, ID id, Class<R> type, Function<ID, R> dbFallback, Long time, TimeUnit unit) {//1.从redis中查询商铺缓存String json = stringRedisTemplate.opsForValue().get(CACHE_SHOP_KEY + id);// 2.判断是否存在if (StrUtil.isNotBlank(json)) {//  3.存在,做反序列化,返回return JSONUtil.toBean(json, type);}//判断命中的是否是空值if (json != null) {return null;}//  4.不存在,根据id查询数据库 我们工具类不清楚实体类以及数据库方法,所以我们需要让调用者将这段逻辑提供给我们,使用函数式接口,//有参数,有返回值 ,使用函数式接口//Function<ID,R> dbFallback,ID为参数,R为返回值R r = dbFallback.apply(id);//  5.不存在,返回错误if (r == null) {//  6.不存在,写入redisstringRedisTemplate.opsForValue().set(KeyPrefix + id, "", CACHE_NULL_TTL, TimeUnit.MINUTES);//  5.不存在,返回错误return null;}//存在,写入redis//时间不能够写死,需要根据业务来定this.set(KeyPrefix + id, r, time, unit);return r;}​​private static final ExecutorService CACHE_REBUILD_EXECUTOR = Executors.newFixedThreadPool(10);//方法四:根据指定的key查询缓存,并且反序列化成指定类型,利用逻辑过期解决缓存击穿问题public <R ,ID> R queryWithLogicalExpire(String keyPrefix,ID id,Class<R> type,Function<ID,R> dbFallback,Long time,TimeUnit unit){//1.从redis中查询商铺缓存String json = stringRedisTemplate.opsForValue().get(keyPrefix+id);// 2.判断是否存在if(StrUtil.isBlank(json)) {​//  3.不存在,直接返回空return null;}​//4.命中,需要把json反序列化为对象RedisData redisData = JSONUtil.toBean(json, RedisData.class);//  4.存在,判断缓存是否过期//Data实际上是jsonObject对象R r = JSONUtil.toBean((JSONObject) redisData.getData(), type);LocalDateTime expireTime = redisData.getExpireTime();//  5.判断是否过期if(expireTime.isAfter(LocalDateTime.now())) {//  5.1.未过期,直接返回店铺信息return r;}//  6.重建缓存// 6.1.获取互斥锁String lock = LOCK_SHOP_KEY + id;boolean isLock = tryLock(lock);// 6.2.判断是否获取锁成功if(isLock) {//再次检测redis缓存是否过期redisData = JSONUtil.toBean(stringRedisTemplate.opsForValue().get(keyPrefix + id), RedisData.class);if (redisData.getExpireTime().isAfter(LocalDateTime.now())) {//  6.1.未过期,直接返回。return JSONUtil.toBean((JSONObject) redisData.getData(), type);}//  6.3.成功,开启独立线程,实现缓存重建CACHE_REBUILD_EXECUTOR.submit(() -> {try {//  重建缓存R r1 = dbFallback.apply(id);//写入RedissetWithLogicalExpire(keyPrefix+id,r1,time,unit);} catch (Exception e) {throw new RuntimeException(e);} finally {//  释放锁unlock(lock);}});}return r;}private boolean tryLock(String key){//设置有效期时间取决于业务执行时间,一般比业务时间长一些即可。Boolean flag = stringRedisTemplate.opsForValue().setIfAbsent(key, "1", 10, TimeUnit.SECONDS);//建议不要直接返回flag,防止返回空指针,因为Boolean是boolean的包装类,需要进行拆箱操作,可能导致空指针 网络问题或者键不存在但Redis未响应,可能会返回null,因此需要实用工具类判断。改成BooleanUtil.isTrue(flag)。return  BooleanUtil.isTrue(flag);}//  释放锁private void unlock(String key){stringRedisTemplate.delete(key);}​​}
工具类小结:

难点:

  • 在查询函数中返回值的类型是不确定的,还有ID类型也无法确定,要善于利用泛型,在数据类型不确定的情况下去指定对应的类型,由调用者告知工具类真实类型,从而做出泛型的推断

  • 在封装查询逻辑时,牵扯到数据库查询,而调用者的数据库类型及查询方式以及实体类都不得而知,都需要让调用者告知如何查询,而查数据库是一段函数,因此调用者需要传入一段函数,这就是用到了函数式编程,因为是根据ID查询后返回,有参数以及返回值,正对应了Java中的Function<参数,返回值 >,要调用者传递进来。

希望对大家有所帮助

相关文章:

Redis--缓存工具封装

经过前面的学习&#xff0c;发现缓存中的问题&#xff0c;无论是缓存穿透&#xff0c;缓存雪崩&#xff0c;还是缓存击穿&#xff0c;这些问题的解决方案业务代码逻辑都很复杂&#xff0c;我们也不应该每次都来重写这些逻辑&#xff0c;我们可以将其封装成工具。而在封装的时候…...

python:在 PyMOL 中如何查看和使用内置示例文件?

参阅&#xff1a;开源版PyMol安装保姆级教程 百度网盘下载 提取码&#xff1a;csub pip show pymol 简介: PyMOL是一个Python增强的分子图形工具。它擅长蛋白质、小分子、密度、表面和轨迹的3D可视化。它还包括分子编辑、射线追踪和动画。 可视化示例‌&#xff1a;打开 PyM…...

SpringCloud——Docker

1.命令解读 docker run -d 解释&#xff1a;创建并运行一个容器&#xff0c;-d则是让容器以后台进程运行 --name mysql 解释&#xff1a; 给容器起个名字叫mysql -p 3306:3306 解释&#xff1a;-p 宿主机端口:容器内端口&#xff0c;设置端口映射 注意&#xff1a; 1、…...

机器学习:欠拟合、过拟合、正则化

本文目录&#xff1a; 一、欠拟合二、过拟合三、拟合问题原因及解决办法四、正则化&#xff1a;尽量减少高次幂特征的影响&#xff08;一&#xff09;L1正则化&#xff08;二&#xff09;L2正则化&#xff08;三&#xff09;L1正则化与L2正则化的对比 五、正好拟合代码&#xf…...

运用集合知识做斗地主案例

方法中可变参数 一种特殊形参&#xff0c;定义在方法&#xff0c;构造器的形参列表里&#xff0c;格式&#xff1a;数据类型...参数名称&#xff1b; 可变参数的特点和好处 特点&#xff1a;可以不传数据给它&#xff1b;可以传一个或者同时传多个数据给它&#xff1b;也可以…...

《HelloGitHub》第 110 期

兴趣是最好的老师&#xff0c;HelloGitHub 让你对开源感兴趣&#xff01; 简介 HelloGitHub 分享 GitHub 上有趣、入门级的开源项目。 github.com/521xueweihan/HelloGitHub 这里有实战项目、入门教程、黑科技、开源书籍、大厂开源项目等&#xff0c;涵盖多种编程语言 Python、…...

使用 Shell 脚本实现 Spring Boot 项目自动化部署到 Docker(Ubuntu 服务器)

使用 Shell 脚本实现 Spring Boot 项目自动化部署到 Docker&#xff08;Ubuntu 服务器&#xff09; 在日常项目开发中&#xff0c;我们经常会将 Spring Boot 项目打包并部署到服务器上的 Docker 环境中。为了提升效率、减少重复操作&#xff0c;我们可以通过 Shell 脚本实现自动…...

day023-网络基础与OSI七层模型

文章目录 1. 网络基础知识点1.1 网络中的单位1.2 查看实时网速&#xff1a;iftop1.3 交换机、路由器 2. 路由表2.1 查看路由表的命令2.2 路由追踪命令 3. 通用网站网络架构4. 局域网上网原理-NAT5. 虚拟机上网原理6. 虚拟机的网络模式6.1 NAT模式6.2 桥接模式6.3 仅主机模式 7.…...

SpringAI系列4: Tool Calling 工具调用 【感觉这版本有bug】

前言&#xff1a;在最近发布的 Spring AI 1.0.0.M6 版本中&#xff0c;其中一个重大变化是 Function Calling 被废弃&#xff0c;被 Tool Calling 取代。Tool Calling工具调用&#xff08;也称为函数调用&#xff09;是AI应用中的常见模式&#xff0c;允许模型通过一组API或工具…...

机器人--里程计

教程 轮式里程计视频讲解 里程计分类 ros--odometry 什么是里程计 里程计是一种利用从移动传感器获得的数据来估计物体位置随时间的变化而改变的方法。该方法被用在许多机器人系统来估计机器人相对于初始位置移动的距离。 注意&#xff1a;里程计是一套算法&#xff0c;不…...

设计模式——原型设计模式(创建型)

摘要 本文详细介绍了原型设计模式&#xff0c;这是一种创建型设计模式&#xff0c;通过复制现有对象&#xff08;原型&#xff09;来创建新对象&#xff0c;避免使用new关键字&#xff0c;可提高性能并简化对象创建逻辑。文章阐述了其优点&#xff0c;如提高性能、动态扩展和简…...

react库:class-variance-authority

文章目录 前言一、cva 的核心作用二、代码逐层解析参数详解基础样式&#xff08;第一个参数&#xff09;&#xff1a;variant&#xff1a;定义颜色/风格变体&#xff08;如 default、destructive&#xff09;。size&#xff1a;定义尺寸变体&#xff08;如 sm、lg&#xff09;。…...

通过mqtt 点灯

1 解析mqtt 传过来的json 用cjson 解析。 2 类似mvc的结构&#xff0c;调用具体的动作函数 定义设备处理结构体&#xff1a;使用结构体数组映射设备名称与处理函数&#xff0c;实现可扩展的指令分发分离设备逻辑&#xff1a;为每个设备&#xff08;如 LED、Motor&#xff0…...

随笔笔记记录5.28

1.setOptMode -opt_leakage_to_dynamic_ratio 调整漏电与动态功耗的优化权重&#xff08; 1.0 表示仅优化漏电&#xff09;。 需指定-opt_power_effort&#xff08;none | low | high&#xff09;&#xff0c;同时使用 2.set_ccopt_property max_source_to_sink_net_length …...

大数据-273 Spark MLib - 基础介绍 机器学习算法 决策树 分类原则 分类原理 基尼系数 熵

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 大模型篇章已经开始&#xff01; 目前已经更新到了第 22 篇&#xff1a;大语言模型 22 - MCP 自动操作 FigmaCursor 自动设计原型 Java篇开…...

基于 Spring Boot + Vue 的墙绘产品展示交易平台设计与实现【含源码+文档】

项目简介 本系统是一个基于 Spring Boot Vue 技术栈开发的墙绘产品展示交易平台&#xff0c;旨在提供一个高效、便捷的在线商城平台&#xff0c;方便用户浏览、选购墙绘产品&#xff0c;并提供管理员进行商品管理、订单管理等功能。系统采用了前后端分离的架构&#xff0c;前…...

【机器学习】支持向量机

文章目录 一、支持向量机简述1.概念2.基本概念3.算法介绍4.线性可分5.算法流程 二、实验1.代码介绍2.模型流程3.实验结果4.实验小结 一、支持向量机简述 1.概念 支持向量机&#xff08;SVM&#xff09;是一类按监督学习方式对数据进行二元分类的广义线性分类器&#xff0c;其…...

ONLYOFFICE深度解锁系列.4-OnlyOffice客户端原理-真的不支持多端同步

最近很多客户多要求直接部署onlyoffice服务端,还问能否和onlyoffice的客户端进行文件同步,当时真是一脸懵,还有的是老客户,已经安装了onlyoffice协作空间的,也在问如何配置客户端和协作空间的对接。由于问的人太多了,这里统一回复,先说结论,再说原理: 1.onlyoffice document s…...

LLMTIME: 不用微调!如何用大模型玩转时间序列预测?

今天是端午节&#xff0c;端午安康&#xff01;值此传统佳节之际&#xff0c;我想和大家分享一篇关于基于大语言模型的时序预测算法——LLMTIME。随着人工智能技术的飞速发展&#xff0c;利用大型预训练语言模型&#xff08;LLM&#xff09;进行时间序列预测成为一个新兴且极具…...

2.从0开始搭建vue项目(node.js,vue3,Ts,ES6)

从“0到跑起来一个 Vue 项目”&#xff0c;重点是各个工具之间的关联关系、职责边界和技术演化脉络。 从你写代码 → 到代码能跑起来 → 再到代码可以部署上线&#xff0c;每一步都有不同的工具参与。 &#x1f63a;&#x1f63a;1. 安装 Node.js —— 万事的根基 Node.js 是…...

MySQL 高可用实现方案详解

MySQL 高可用实现方案详解 一、高可用核心概念 高可用性(High Availability)指系统能够持续提供服务的能力,通常用可用性=正常服务时间/(正常服务时间+故障时间)来衡量,99.99%可用性表示年故障时间不超过52.6分钟。 MySQL实现高可用需要解决以下几个关键问题: 故障自动检测…...

【pycharm】如何连接远程仓库进行版本管理(应用版本)

软件&#xff1a;Pycharm OS&#xff1a;Windows 一、Git基础设置 这里略过Git安装&#xff0c;需要可以参考&#xff1a;windows安装git&#xff08;全网最详细&#xff0c;保姆教程&#xff09;-CSDN博客 1. 配置Git 打开GitBash。分次输入下列命令。 git config --…...

linux 1.0.7

用户和权限的含义与作用 linux中的用户和文件 用户的权限是非常重要的 而且有些程序需要使用管理员身份去执行 这些都是非常重要的 不可能让所有的人拥有所有的权限 这样的工具可以避免非法的手段来修改计算机中的数据 linux之所以安全还是权限管理做的很棒 每个登录的用户都有…...

【Rust 轻松构建轻量级多端桌面应用】

使用 Tauri 框架构建跨平台应用 Tauri 是一个基于 Rust 的轻量级框架&#xff0c;可替代 Electron&#xff0c;用于构建高性能、低资源占用的桌面应用。其核心优势在于利用系统原生 WebView 而非捆绑 Chromium&#xff0c;显著减小应用体积。 安装 Tauri 需要先配置 Rust 环境…...

IEEE P370:用于高达 50 GHz 互连的夹具设计和数据质量公制标准

大多数高频仪器&#xff0c;如矢量网络分析仪 &#xff08;VNA&#xff09; 和时域反射仪 &#xff08;TDR&#xff09;&#xff0c;都可以在同轴接口的末端进行非常好的测量。然而&#xff0c;复杂系统中使用的互连很少具有同轴接口。用于表征这些设备的夹具的设计和实施会对测…...

青少年编程与数学 02-020 C#程序设计基础 09课题、面向对象编程

青少年编程与数学 02-020 C#程序设计基础 09课题、面向对象编程 一、概述1. 对象&#xff08;Object&#xff09;2. 类&#xff08;Class&#xff09;3. 封装&#xff08;Encapsulation&#xff09;4. 继承&#xff08;Inheritance&#xff09;5. 多态&#xff08;Polymorphism…...

Denoising Autoencoders 视频截图 DAEs简单实现 kaggle 去噪编码器

https://www.bilibili.com/video/BV1syzrYaEtw Denoising Autoencoders (DAEs) 是一种无监督学习模型&#xff0c;属于自动编码器&#xff08;Autoencoder&#xff09;的一种扩展形式。它们的目标是通过训练神经网络来学习数据的鲁棒表示&#xff08;robust representation&a…...

GoogLeNet网络模型

GoogLeNet网络模型 诞生背景 在2014年的ImageNet图像识别挑战赛中&#xff0c;一个GoogLeNet的网络架构大放异彩&#xff0c;与VGG不同的是&#xff0c;VGG用的是3*3的卷积&#xff0c;而GoogLeNet从1*1到7*7的卷积核都用&#xff0c;也就是使用不同大小的卷积核组合。 网络…...

LeetCode Hot100 (贪心)

121. 买卖股票的最佳时机 题意 给定一个数组 prices &#xff0c;它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。你只能选择 某一天 买入这只股票&#xff0c;并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。返回你可以从…...

仿真科普|弥合市场需求断层,高性能仿真,“性能”与“安全”如何兼得?

2025年3月&#xff0c;塔塔科技&#xff08;Tata Technologies&#xff09;确认曾在去年遭受勒索软件组织“猎手国际”&#xff08;Hunters International&#xff09;的攻击&#xff0c;1.4TB工程数据被窃取&#xff0c;涉及航空发动机热障涂层工艺参数等超过 73 万份文件。 X…...