七、Redis 缓存 —— 超详细操作演示!

七、Redis 缓存 —— 超详细操作演示!

    • 七、Redis 缓存
      • 7.1 Jedis 客户端
          • 7.1.1 Jedis 简介
          • 7.1.2 创建工程
          • 7.1.3 使用 Jedis 实例
          • 7.1.4 使用 JedisPool
          • 7.1.5 使用 JedisPooled
          • 7.1.6 连接 Sentinel 高可用集群
          • 7.1.7 连接分布式系统
          • 7.1.8 操作事务
      • 7.2 金融产品交易平台
      • 7.3 高并发问题
          • 7.3.1 缓存穿透
          • 7.3.2 缓存击穿
          • 7.3.3 缓存雪崩
          • 7.3.4 数据库缓存双写不一致

数据库系列文章:

关系型数据库:

  • MySQL —— 基础语法大全
  • MySQL —— 进阶


非关系型数据库:

  • 一、Redis 的安装与配置
  • 二、Redis 基本命令(上)
  • 三、Redis 基本命令(下)
  • 四、Redis 持久化
  • 五、Redis 主从集群
  • 六、Redis 分布式系统

七、Redis 缓存

7.1 Jedis 客户端

7.1.1 Jedis 简介

    Jedis 是一个 基于 java 的 Redis 客户端连接工具 ,旨在提升性能易用性 。 其 github 上的官网地址为: https://github.com/redis/jedis 。

7.1.2 创建工程

    首先创建一个普通的 Maven 工程 01-jedis ,然后在 POM 文件中添加 Jedis 与 Junit 依赖。

<properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> 
</properties> <dependencies> <!--jedis依赖--> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>4.2.0</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> 
</dependencies>
7.1.3 使用 Jedis 实例

    Jedis 基本使用十分简单, 其提供了非常丰富的操作 Redis 的方法,而这些方法名几乎与 Redis 命令相同。 在每次使用时直接创建 Jedis 实例即可。在 Jedis 实例 创建好之后, Jedis 底层实际会创建一个到指定 Redis 服务器Socket 连接 。所以 ,为 了节省系统资源网络带宽 在每次使用完 Jedis 实例 之后,需要立即调用 close() 方法将 连接关闭。

    首先,需要在工程的 src/test/java 下创建测试类 JedisTest

⭐️(1) value 为 String 的测试

@Test
public void test01() {Jedis jedis = new Jedis("redis", 6379);jedis.set("name", "张三");jedis.mset("age", "23", "depart", "市场部");System.out.println("name = " + jedis.get("name"));System.out.println("age = " + jedis.get("age"));System.out.println("depart = " + jedis.get("depart"));jedis.close();
}

在这里插入图片描述
在这里插入图片描述

⭐️(2) value 为 Hash 的测试

@Test
public void test02() {Jedis jedis = new Jedis("redis", 6379);jedis.hset("emp", "name", "Tom");Map<String, String> map = new HashMap<>();map.put("age", "24");map.put("depart", "行政部");jedis.hset("emp", map);System.out.println("emp.name = " + jedis.hget("emp", "name"));List<String> emp = jedis.hmget("emp", "name", "age", "depart");System.out.println("emp = " + emp);jedis.close();
}

在这里插入图片描述

⭐️(3) value 为 List 的测试

// value为List的情况
@Test
public void test03() {Jedis jedis = new Jedis("redis", 6379);jedis.rpush("cities", "北京", "上海", "广州");List<String> cities = jedis.lrange("cities", 0, -1);System.out.println("cities = " + cities);jedis.close();
}

在这里插入图片描述

⭐️(4) value 为 Set 的测试

// value为Set的情况
@Test
public void test04() {Jedis jedis = new Jedis("redis", 6379);jedis.sadd("courses", "Redis", "RocketMQ", "Zookeeper", "Kafka");Set<String> courses = jedis.smembers("courses");System.out.println("courese = " + courses);jedis.close();
}

在这里插入图片描述

⭐️(5) value 为 Zset 的测试

// value为ZSet的情况
@Test
public void test05() {Jedis jedis = new Jedis("redis", 6379);jedis.zadd("sales", 50, "Benz");jedis.zadd("sales", 40, "BMW");jedis.zadd("sales", 30, "Audi");jedis.zadd("sales", 80, "Tesla");jedis.zadd("sales", 120, "BYD");List<String> top3 = jedis.zrevrange("sales", 0, 2);System.out.println("top3 = " + top3);List<Tuple> sales = jedis.zrevrangeWithScores("sales", 0, -1);for (Tuple sale : sales) {System.out.println(sale.getScore() + ":" + sale.getElement());}jedis.close();
}

在这里插入图片描述

7.1.4 使用 JedisPool

    如果应用非常 频繁地 创建和销毁 Jedis 实例 虽然节省了系统资源与网络带宽,但会大大降低系统性能。 因为 创建和销毁 Socket 连接 是比较耗时的 。 此时可以使用 Jedis 连接池 来解决该问题。

    使用 JedisPool 与使用 Jedis 实例的区别是, JedisPool全局性的整个类只需创建一次即可,然后每次需要操作 Redis 时,只需从 JedisPool 中拿出一个 Jedis 实例 直接使用即可。使用完毕后,无需释放 Jedis 实例,只需 返回 JedisPool 即可。

public class JedisPoolTest {private JedisPool jedisPool = new JedisPool("redis", 6379);// value为String的情况@Testpublic void test01() {try(Jedis jedis = jedisPool.getResource()) {jedis.set("name", "张三");jedis.mset("age", "23", "depart", "市场部");System.out.println("name = " + jedis.get("name"));System.out.println("age = " + jedis.get("age"));System.out.println("depart = " + jedis.get("depart"));}}
}

在这里插入图片描述

7.1.5 使用 JedisPooled

    对于每次对 Redis 的操作都需要使用 try-with-resource 块是比较麻烦的,而使用 JedisPooled 则无需再使用该结构来自动释放资源了。

public class JedisPooledTest {private JedisPooled jedis = new JedisPooled("192.168.216.128", 6379);// value为String的情况@Testpublic void test01() {jedis.set("name", "张三");jedis.mset("age", "23", "depart", "市场部");System.out.println("name = " + jedis.get("name"));System.out.println("age = " + jedis.get("age"));System.out.println("depart = " + jedis.get("depart"));}
}

在这里插入图片描述

7.1.6 连接 Sentinel 高可用集群

    对于 Sentinel 高可用集群的连接,直接使用 JedisSentinelPool 即可。在该客户端只需注册所有 Sentinel 节点 及其监控的 Master 的名称即可,无需出现 master -slave 的任何地址信息。其采用的也是 JedisPool ,使用完毕的 Jedis 也需要通过 close() 方法将其返回给 连接池

public class JedisSentinelPoolTest {private JedisSentinelPool jedisPool;{Set<String> sentinel =  new HashSet<>();sentinel.add("192.168.216.128:26380");sentinel.add("192.168.216.128:26381");sentinel.add("192.168.216.128:26382");jedisPool = new JedisSentinelPool("mymaster", sentinel);}// value为String的情况@Testpublic void test01() {try(Jedis jedis =  jedisPool.getResource()) {jedis.set("name", "张三");jedis.mset("age", "23", "depart", "市场部");System.out.println("name = " + jedis.get("name"));System.out.println("age = " + jedis.get("age"));System.out.println("depart = " + jedis.get("depart"));}}
}

在这里插入图片描述
在这里插入图片描述

7.1.7 连接分布式系统

    对于 Redis 的分布式系统的连接,直接使用 JedisCluster 即可。其底层采用的也是 Jedis连接池技术。每次使用完毕后,无需显式关闭,其会自动关闭

    对于 JedisCluster 常用的 构造器 有两个。

  • 一个是 只需一个集群节点构造器,这个节点可以是集群中的任意节点,只要连接上了该节点,就连接上了整个集群。但该构造器存在一个风险:其指定的这个节点在连接之前恰好宕机,那么该客户端将无法连接上集群
  • 所以,推荐使用第二个 构造器,即将集群中所有节点全部罗列出来。这样就会避免这种风险了 。
public class JedisClusterTest{private JedisCluster jedisCluster;{// 连接CLuster中的任意主机// HostAndPort node = new HostAndPort("redis", 6380);// jedisCluster = new JedisCluster(node);//连接整个CLusterHashSet<HostAndPort> nodes = new HashSet<>();nodes.add(new HostAndPort("redis", 6380));nodes.add(new HostAndPort("redis", 6381));nodes.add(new HostAndPort("redis", 6382));nodes.add(new HostAndPort("redis", 6383));nodes.add(new HostAndPort("redis", 6384));nodes.add(new HostAndPort("redis", 6385));jedisCluster = new JedisCluster(nodes);}// value为String的情况@Testpublic void test01() {jedisCluster,set("name", "张三");// 会出现跨槽,报错// jedisClustermset("age", "23", "depart","行政部");System.out.println("name = " + jedisCluster.get("name"));}
}

在这里插入图片描述

7.1.8 操作事务

    对于 Redis 事务 的操作, Jedis 提供了 multi()watch()unwatch() 方法来对应 Redis 中的 multiwatchunwatch 命令。 Jedis 的 multi() 方法返回一个 Transaction 对象,其 exec()discard() 方法用于 执行和取消事务的执行

⭐️(1) 抛出 Java 异常

public class JedisTxTest {private JedisPool jedisPool = new JedisPool("192.168.216.128", 6379);// value为String的情况@Testpublic void test01() {try(Jedis jedis =  jedisPool.getResource()) {jedis.set("name", "张三");jedis.mset("age", "23");Transaction multi = jedis.multi();try{multi.set("name", "李四");// 构造一个 Java 异常int i = 3 / 0;multi.set("age", "24");multi.exec();}catch (Exception e){// 一旦发生异常,全部回滚multi.discard();}finally {System.out.println("name = " + jedis.get("name"));System.out.println("age = " + jedis.get("age"));}}}
}

在这里插入图片描述

    其输出结果为全部回滚的结果

⭐️(2) 让 Redis 异常

@Test
public void test02() {try(Jedis jedis = jedisPool.getResource()) {jedis.set("name", "张三");jedis.mset("age", "23");Transaction tx = jedis.multi();try {tx.set("name", "李四");// 构造出一个Redis异常tx.incr("name");tx.set("age", "24");tx.exec();} catch (Exception e) {// 发生异常,全部回滚tx.discard();} finally {System.out.println("name = " + jedis.get("name"));System.out.println("age = " + jedis.get("age"));}}
}

在这里插入图片描述

    其输出结果为修改过的值。说明 Redis 运行时 抛出的异常不会被 Java 代码 捕获到,其 不会影响 Java 代码的执行。

⭐️(3) watch()

@Test
public void test03() {try(Jedis jedis = jedisPool.getResource()) {jedis.mset("age", "23");System.out.println("age增一前的值:" + jedis.get("age"));jedis.watch("age");Transaction tx = jedis.multi();try {tx.incr("age");tx.exec();} catch (Exception e) {tx.discard();} finally {System.out.println("age增一后的值:" + jedis.get("age"));}}
}

在这里插入图片描述

7.2 金融产品交易平台

7.2.1 Spring Boot 整合 Redis

7.2.2 Redis 操作模板

    Spring Boot 中可以直接使用 Jedis 实现对 Redis 的操作,但一般不这样用,而是使用 Redis 操作模板 RedisTemplate 类的实例来操作 Redis

    RedisTemplate 类是一个对 Redis 进行操作的模板类。该模板类中具有很多方法,这些方法很多与 Redis 操作命令同名或类似。例如, delete()keys()scan(),还有事务相关的 multi()exec()discard()watch() 等。当然还有获取对各种 Value 类型进行操作的操作实例的两类方法 boundXxxOps(k)opsForXxx()

7.2.3 需求

    下面通过一个例子来说明 Spring Boot 是如何与 Redis 进行 整合 的。

    对于一个资深成熟的金融产品交易平台,其用户端首页一般会展示其最新金融产品列表同时还为用户提供了产品查询功能。另外,为了显示平台的实力与信誉,在平台首页非常显眼的位置还会展示平台已完成的总交易额注册用户数量。对于管理端,管理员可通过管理页面修改产品上架新产品下架老产品

    为了方便了解 RedisSpring Boot 的整合流程,这里对系统进行了简化:

  • 用户端 首页提供根据金融产品名称的查询,显眼位置仅展示交易总额。
  • 管理端 仅实现上架新产品功能

7.2.4 创建 SSM 工程

⭐️(1) 创建工程

    定义一个 Spring Boot 工程,并命名为 ssm

⭐️(2) 定义 pom 文件

    在 pom 文件中需要导入 MySQL 驱动Druid 等大量依赖。 POM 文件中的重要内容如下:

	<properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><maven.compiler.source>1.8</maven.compiler.source><maven.compiler.target>1.8</maven.compiler.target></properties><dependencies><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>1.3.2</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.47</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.12</version></dependency><dependency><groupId>org.apache.tomcat.embed</groupId><artifactId>tomcat-embed-jasper</artifactId></dependency><dependency><groupId>javax.servlet</groupId><artifactId>jstl</artifactId><version>1.2</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><build><resources><resource><directory>src/main/java</directory><includes><include>**/*.xml</include></includes></resource><resource><directory>src/main/webapp</directory><targetPath>META-INF/resources</targetPath><includes><include>**/*.*</include></includes></resource></resources></build>

⭐️(3) 修改主配置文件

    在主配置文件中配置 MyBatisSpring日志等配置:

⭐️(4) 实体类 Product

平台交易总额,即“产品募集结束日期”小于“当前查询日期”的“产品募集总额”之和。

⭐️(5) 创建数据库表

    在 test 数据库中创建一个名称为 product 的表。创建的 sql 文件如下,直接运行该文件即可。

⭐️(6) 定义 index.jsp

    在 src/main 下创建 webap 目录,用于存放 jsp 文件。这就是一个普通的目录,无需执行 Mark Directory As 。在 webapp 目录中创建一个 index.jsp 文件。

⭐️(7) 定义 manager.jsp

    在 webapp 目录下再创建一个 jsp 子目录,在其中定义 manager.jsp

⭐️(8) 定义 result.jsp

    在 webapp/jsp 中定义 result.jsp

⭐️(9) ProductController 类

A、 indexHandle()

B、 registerHandle()

C、 listHandle()

⭐️(10) ProductService 接口

⭐️(11) ProductServiceImpl 类

A、 saveProduct()

B、 三个 find 方法

⭐️(12) ProductDao 接口

⭐️(13) 映射文件

⭐️(14) Application 启动类

7.2.5 创建 SSRM 工程

7.3 高并发问题

    Redis做缓存虽减轻了 DBMS 的压力,减小了 RT ,但在 高并发 情况下也是可能会出现各种问题的。

7.3.1 缓存穿透

    当用户访问的 数据 既不在缓存 也不在数据库中 时,就会导致每个用户查询都会 “穿透缓存直抵数据库。这种情况就称为缓存穿透。当高并发的访问请求到达时,缓存穿透不仅增加了响应时间,而且还会引发对 DBMS 的高并发查询,这种 高并发查询 很可能会导致DBMS 的崩溃

    缓存穿透产生的主要原因有两个:一是在数据库中 没有 相应的查询结果,二是查询结果为 时,不对查询结果进行缓存。所以,针对以上两点,解决方案也有两个:

  • 非法请求 进行 限制
  • 结果为空 的查询给出 默认值
7.3.2 缓存击穿

    对于 某一个缓存 ,在高并发情况下若其访问量特别巨大,当 该缓存的有效时限到达时,可能会出现大量的访问都要重建该缓存,即这些访问请求发现缓存中没有该数据,则立即到 DBMS 中进行查询,那么这就有可能会引发对 DBMS高并发查询,从而接导致 DBMS 的崩溃。这种情况称为缓存击穿,而该缓存数据称为 热点数据

    对于缓存击穿 的解决方案,较典型的是使用 “双重检测锁 ” 机制。

7.3.3 缓存雪崩

    对于缓存中的数据,很多都是有过期时间的。若 大量缓存过期时间在同一很短的时间段内几乎同时到达,那么在高并发访问场景下就可能会引发对 DBMS 的高并发查询,而这将可能直接导致 DBMS 的崩溃。这种情况称为 缓存雪崩

    对于缓存雪崩没有很直接的解决方案,最好的解决方案就是 预防 ,即提前规划好缓存的过期时间。

  • 要么就是让缓存 永久有效,当 DB 中数据发生变化时清除相应的缓存。
  • 如果 DBMS 采用的是 分布式部署,则将热点数据 均匀分布在不同数据库节点中,将可能到来的访问负载均衡开来。
7.3.4 数据库缓存双写不一致

    以上三种情况都是针对 高并发 场景中可能会出现的问题,而数据库缓存双写不一致问题,则是在 高并发 场景下可能会出现的问题。

    对于数据库缓存 双写不一致 问题,以下两种场景下均有可能会发生:

⭐️(1) “修改 DB 更新缓存” 场景

    对于具有缓存 warmup 功能的系统, DBMS 中常用数据的变更,都会引发缓存中相关数据的更新。在 高并发 请求场景下,若多个请求要对 DBMS 中同一个数据进行修改,修改后还需要更新缓存中相关数据,那么就有可能会出现 缓存数据库中 数据 不一致的情况。

在这里插入图片描述

⭐️(2) “修改 DB 删除缓存” 场景

    在很多系统中是没有缓存 warmup 功能的,为了保持缓存与数据库数据的一致性,一般都是在对数据库执行了写操作后,就会 删除 相应缓存

    在 高并发读写 请求场景下,若这些请求对 DBMS 中同一个数据的操作既包含也包含,且修改后还要删除缓存中相关数据,那么就有可能会出现缓存与数据库中数据不一致的情况。

在这里插入图片描述

⭐️(3) 解决方案:延迟双删

    延迟双删 方案是专门针对于“ 修改DB 删除缓存 ” 场景的解决方案。但该方案并不能彻底解决数据不一致的状况,其只可能降低发生数据不一致的概率。

    延迟双删方案是指,在写操作完毕后会立即执行一次缓存的删除操作,然后再停上一段时间(一般为几秒)后再进行一次删除。而两次删除中间的间隔时长,要大于一次 缓存写操作时长

在这里插入图片描述

⭐️(4) 解决方案:队列

    以上两种场景中,只所以会出现 数据库缓存数据不一致,主要是因为 对请求的处理出现了并行。只要将请求写入到一个统一的队列,只有处理完一个请求后才可处理下一个请求,即使系统对用户请求的处理 串行化,就可以完全解决数据不一致的问题。

⭐️(5) 解决方案:分布式锁

    使用队列的串行化虽然可以解决数据库与缓存中数据不一致,但系统 失去了并发性,降低了性能。使用 分布式锁 可以在不影响并发性的前提下,协调各处理线程间的关系,使数据
库与缓存中的数据达成一致性。

    只需要对数据库中的这个共享数据的访问通过 分布式锁 来协调对其的操作访问即可。



注:仅供学习参考,如有不足,欢迎指正!

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

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

相关文章

Python怎么修改进程名称

目录 一、进程名称的概念 二、Python修改进程名称的方法 三、代码示例与使用说明 四、注意事项 五、适用场景 六、总结 Python是一种强大的编程语言&#xff0c;广泛应用于各种应用程序的开发。在Python中&#xff0c;修改进程名称可以通过多种方式实现。下面我们将深入探…

python c语言 代码动态检查,python c语言语法分析

大家好&#xff0c;小编来为大家解答以下问题&#xff0c;python c语言 代码动态检查&#xff0c;python c语言语法分析&#xff0c;今天让我们一起来看看吧&#xff01; Source code download: 本文相关源码 初学编程&#xff0c;应该学习哪一门编程语言&#xff0c;有不少人感…

项目经理面试10问

今天我们来说说项目经理专业面试的十条经验总结。如果你认真阅读并思考&#xff0c;相信对在屏幕前的你会有所帮助和启发。 1、请做一下自我介绍 自我介绍很重要。无论面试什么岗位&#xff0c;面试官通常都会问你一个最常见的问题&#xff1a;“请做一下自我介绍。” 在准备…

Unity坦克大战开发全流程——开始场景——开始界面

开始场景——开始界面 step1&#xff1a;设置UI 反正按照这张图拼就行了 step2&#xff1a;写脚本 前面的拼UI都是些比较机械化的工作&#xff0c;直到这里写代码的时候才真正开始有点意思了&#xff0c;从这里开始&#xff0c;我们就要利用面向对象的思路来进行分析&#xff1…

虾皮跨境电商选品有哪些规则

如何在虾皮&#xff08;Shopee&#xff09;平台上进行跨境电商选品在如今全球化的商业环境中&#xff0c;跨境电商已成为许多卖家拓展业务的重要途径。虾皮&#xff08;Shopee&#xff09;作为一家知名的跨境电商平台&#xff0c;为卖家提供了丰富的销售机会。然而&#xff0c;…

【C++核心编程(二)】

一、类和对象 C面向对象的三大特性为:封装、继承、多态。 C认为万事万物都皆为对象&#xff0c;对象上有其属性和行为。 例如: 人可以作为对象&#xff0c;属性有姓名、年龄、身高、体重...&#xff0c;行为有走、跑、跳、吃饭、唱歌... 车也可以作为对象&#xff0c;属性…

HTML中的主根元素、文档元数据、分区根元素、内容分区、文本内容 和 内联文本语义

本文主要介绍了HTML中主根元素<html>、文档元数据<base>、<head>、<link>、<meta>、<style>、<title>、分区根元素<body>、内容分区<address>、<article>、<aside>、<footer>、<h1> (en-US), &…

3dmax全景图用什么渲染 全景图云渲染使用教程

在给客户展示设计概念时&#xff0c;应用3ds Max创建的全景图是一个高效直观的方法。这种方式不仅可以全方位地呈现整个空间&#xff0c;让客户沉浸式地感受设计师的创意&#xff0c;而且在展现大型空间设计&#xff0c;如展览馆或者会议室等&#xff0c;效果尤其显著&#xff…

在mac上怎么方便的编辑xml文件

在Mac上 XML 文件不能默认以较直观的方式在“文本编辑”中打开&#xff0c;如果已安装 Xcode&#xff0c;你可以使用 Xcode 打开 XML 文件。在 Xcode 中&#xff0c;XML 文件通常会以可视化的方式显示&#xff0c;使得编辑更加直观&#xff0c;但是如果你不想安装 XCode&#x…

Win10 开机突然时出现0xc000014c错误怎么办?

环境&#xff1a; Win10 专业版 问题描述&#xff1a; Win10 开机突然时出现0xc000014c错误怎么办&#xff1f; 尝试F8模式也进不了还是这个画面 文件&#xff1a;\Windows\System32\config\system 状态&#xff1a;0xc000014c 信息&#xff1a;无法加载操作系统&#xff…

摆烂式学习ssh

摆烂式学习ssh ssh工作原理ssh基本使用sshd配置文件密钥登录1.客户端2.服务器3.注意事项4.使用密钥登录测试 ssh高级使用技巧1.在非正规端口启动2.rsync 命令3.透过 ssh 通道加密原本无加密的服务4.以ssh信道配合x server 传递图形接口5.ssh配合virtualbox虚拟机使用技巧 ssh工…

Python高级用法:装饰器(decorator)

装饰器&#xff08;decorator&#xff09; Python装饰器的作用是使函数包装与方法包装&#xff08;一个函数&#xff0c;接受函数并返回其增强函数&#xff09;变得更容易阅读和理解。最初的使用场景是在方法定义的开头能够将其定义为类方法或静态方法。 不使用装饰器的代码如…

主干网络篇 | YOLOv8 更换骨干网络之 ResNet50/ResNet101 | 原论文一比一复现

论文地址:https://arxiv.org/abs/1512.03385v1 更深层的神经网络更难以训练。我们提出了一个残差学习框架,以便于训练比以往使用的网络更深层的网络。我们明确地将层重构为学习相对于层输入的残差函数,而不是学习无参考的函数。我们提供了全面的实证证据,表明这些残差网络…

Unity 欧盟UMP用户隐私协议Android接入指南

Unity 欧盟UMP用户协议Android接入指南 官方文档链接开始接入mainTemplate.gradle 中引入CustomUnityPlayerActivity 导入UMP相关的包java类中新增字段初始化UMPSDK方法调用![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/d882171b068c46a1b956e80425f3a9cf.png)测…

java实现大文件分片上传

背景&#xff1a; 公司后台管理系统有个需求&#xff0c;需要上传体积比较大的文件&#xff1a;500M&#xff0d;1024M&#xff1b;此时普通的文件上传显然有些吃力了&#xff0c;加上我司服务器配置本就不高&#xff0c;带宽也不大&#xff0c;所以必须考虑多线程异步上传来提…

mfc100u.dll文件丢失,有五种不同解决方法

在计算机使用过程中&#xff0c;我们经常会遇到一些错误提示&#xff0c;其中之一就是“找不到mfc100u.dll文件”。那么&#xff0c;mfc100u.dll文件到底是什么&#xff1f;为什么会出现丢失的情况&#xff1f;本文将详细介绍mfc100u.dll文件的作用以及丢失的原因&#xff0c;并…

Anaconda下载与超安装详解教程

1 Anaconda 1.1 简介 Anaconda 指的是一个开源的 Python 发行版本&#xff0c;其包含了 conda、Python等180多个科学包及其依赖项。 因为包含了大量的科学包&#xff0c;Anaconda 的下载文件比较大&#xff08;约 477MB&#xff09;&#xff0c;如果只需要某些包&#xff0c;…

安全与认证Week4

目录 本章需要理解的问题 历年题还出现 Web Security (TLS/SSL) 关于网络 使用网络会受到的威胁 各层安全协议 S/MIME、PGP&#xff08;后面和S/MIME一起出现&#xff09;、Kerberos、TLS/SSL 和 IP/IPSec 分别是&#xff1a; S/MIME (Secure/Multipurpose Internet Mail Exten…

DsPdf:GcPdf 7.0 for NET Crack

DsPdf:GcPdf 7.0 用于全面文档控制的功能丰富的 C# .NET PDF API 库 PDF 文档解决方案&#xff08;DsPdf&#xff0c;以前称为 GcPdf&#xff09;可让您快速、高效地生成文档&#xff0c;且无需依赖任何内存。 在 C# .NET 中生成、加载、编辑和保存 PDF 文档 支持多种语言的全…

安装Unity详细教程(如何获取免费个人版许可证)

文章目录 下载Unity Hub安装Unity Hub登录获取免费个人版许可证安装Unity编辑器卸载Unity编辑器 下载Unity Hub 首先&#xff0c;我们需要到Unity的官网下载Unity Hub&#xff1a;Unity CN 我们可以在Unity Hub上管理我们的编辑器版本和项目文件。 安装Unity Hub 然后安装Un…