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

全网最详细RabbitMQ教学包括如何安装环境【RabbitMQ】RabbitMQ + Spring Boot集成零基础入门(基础篇)

目录

  • 一、初始Rabbitmq
    • 1、什么是Rabbitmq,它的概述是什么?
    • 2、RabbitMQ的应用场景
    • 3、RabbitMQ主要组件
    • 4、RabbitMQ 的优点
    • 5、与其他消息队列性能比较
  • 二、RabbitMQ环境安装初始化
  • 三、SpringAMQP+RabbitMQ实战入门(基本API)
    • 1、实战入门(Java API)
      • 一、WorkQueues模型
      • 二、交换机类型
        • 1、Fanout交换机
        • 2、Direct交换机
        • 3、Topic交换机
      • 三、基于注解声明

一、初始Rabbitmq

1、什么是Rabbitmq,它的概述是什么?

RabbitMQ 是一个开源的消息队列中间件,作为消息代理(Message Broker)实现,它负责在不同的应用程序、服务或组件之间传递消息。RabbitMQ 实现了 AMQP(Advanced Message Queuing Protocol)协议,支持可靠的消息传递,确保消息能够在系统中被可靠、顺序地传递,并支持异步和解耦合的通信方式。 其中消息传递的基本模型可以分为 点对点(Point-to-Point)发布/订阅(Publish/Subscribe) 两种类型。

2、RabbitMQ的应用场景

  • 异步处理: RabbitMQ 非常适合需要异步处理的场景。例如,在电商网站中,订单生成后需要异步处理支付、发货等任务,生产者将消息发送到 RabbitMQ,消费者异步处理这些任务。

  • 分布式系统通信解耦: RabbitMQ 可以用作分布式系统中各个服务之间的通信媒介,服务之间通过消息队列进行解耦,避免直接调用和依赖。

  • 事件驱动架构(EDA): 在事件驱动架构中,RabbitMQ 可以作为事件总线,消费者根据事件类型处理不同的业务逻辑。

  • 日志收集与分析: RabbitMQ 可以用于收集和转发日志信息,将日志从不同的系统组件传递到中央日志处理系统。

3、RabbitMQ主要组件

  • publisher:生产者,也就是发送消息的一方

  • consumer:消费者,也就是消费消息的一方

  • queue:队列,存储消息。生产者投递的消息会暂存在消息队列中,等待消费者处理

  • exchange:交换机,负责消息路由。生产者发送的消息由交换机决定投递到哪个队列。

  • Binding(绑定):交换机和队列之间的联系,定义了交换机将消息路由到队列的规则。

  • Message(消息):在生产者和消费者之间传递的数据,通常包括消息体和一些元数据(如路由键、消息头等)。

4、RabbitMQ 的优点

  • 解耦合:生产者和消费者之间不直接交互,它们通过队列进行消息交换,从而解耦应用程序的各个组件。
  • 异步处理:RabbitMQ 支持异步消息传递,允许系统在接收请求时立即响应,并在后台处理任务。
  • 可靠性:支持消息持久化、消息确认等功能,确保消息不会丢失。
  • 扩展性:通过集群和镜像队列,RabbitMQ 可以扩展到多个节点,提供高可用性和负载均衡。
  • 多协议支持:虽然 RabbitMQ 基于 AMQP,但它还可以通过插件支持其他协议,如 MQTT、STOMP 等。

5、与其他消息队列性能比较

在这里插入图片描述

  • 追求可用性:Kafka、 RocketMQ 、RabbitMQ
  • 追求可靠性:RabbitMQ、RocketMQ
  • 追求吞吐能力:RocketMQ、Kafka
  • 追求消息低延迟:RabbitMQ、Kafka
    据统计,目前国内消息队列使用最多的还是RabbitMQ,再加上其各方面都比较均衡,稳定性也好,因此我们课堂上选择RabbitMQ来学习。

二、RabbitMQ环境安装初始化

RabbitMQ详情安装教程地址:教程安装地址

三、SpringAMQP+RabbitMQ实战入门(基本API)

将来我们开发业务功能的时候,肯定不会在控制台收发消息,而是应该基于编程的方式。由于RabbitMQ采用了AMQP协议,因此它具备跨语言的特性。任何语言只要遵循AMQP协议收发消息,都可以与RabbitMQ交互。并且RabbitMQ官方也提供了各种不同语言的客户端。 但是,RabbitMQ官方提供的Java客户端编码相对复杂,一般生产环境下我们更多会结合Spring来使用。而Spring的官方刚好基于RabbitMQ提供了这样一套消息收发的模板工具:SpringAMQP。并且还基于SpringBoot对其实现了自动装配,使用起来非常方便。

Spring AMQP 的官方地址: Spring AMQP SpringAMQP提供了三个功能:

  • 自动声明队列、交换机及其绑定关系
  • 基于注解的监听器模式,异步接收消息
  • 封装了RabbitTemplate工具,用于发送消息

1、实战入门(Java API)

导入依赖

<!--AMQP依赖,包含RabbitMQ-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId>
</dependency>

一、WorkQueues模型

Work queues,任务模型。简单来说就是让多个消费者绑定到一个队列,共同消费队列中的消息.

当消息处理比较耗时的时候,可能生产消息的速度会远远大于消息的消费速度。长此以往,消息就会堆积越来越多,无法及时处理。 此时就可以使用work 模型,多个消费者共同处理消息处理,消息处理的速度就能大大提高了。

1)声明队列

@Configuration
public class FanoutConfig {/*** 第1个队列*/@Beanpublic Queue fanoutQueue1(){return new Queue("simple.queue");}
}

2)消息发送
这次我们往队列中循环发送,模拟出一个大量消息堆积的队列。

/*** workQueue* 向队列中不停发送消息,模拟消息堆积。*/
@Test
public void testWorkQueue() throws InterruptedException {// 队列名称String queueName = "simple.queue";// 消息String message = "hello, message_";for (int i = 0; i < 50; i++) {// 发送消息,每20毫秒发送一次,相当于每秒发送50条消息rabbitTemplate.convertAndSend(queueName, message + i);Thread.sleep(20);}
}

3) 消息接收
要模拟多个消费者绑定同一个队列,我们在consumer服务的SpringRabbitListener中添加2个新的方法(其中**@RabbitListener**用来监听队列):

@RabbitListener(queues = "work.queue")
public void listenWorkQueue1(String msg) throws InterruptedException {System.out.println("消费者1接收到消息:【" + msg + "】" + LocalTime.now());Thread.sleep(20);
}@RabbitListener(queues = "work.queue")
public void listenWorkQueue2(String msg) throws InterruptedException {System.err.println("消费者2........接收到消息:【" + msg + "】" + LocalTime.now());Thread.sleep(200);
}

注意到这两消费者,都设置了Thead.sleep,模拟任务耗时:

消费者1 sleep了20毫秒,相当于每秒钟处理50个消息

消费者2 sleep了200毫秒,相当于每秒处理5个消息

4)测试
启动ConsumerApplication后,在执行publisher服务中刚刚编写的发送测试方法testWorkQueue。 最终结果如下:

消费者1和消费者2竟然每人消费了25条消息:

消费者1很快完成了自己的25条消息

消费者2却在缓慢的处理自己的25条消息。

也就是说消息是平均分配给每个消费者,并没有考虑到消费者的处理能力。**导致1个消费者空闲,另一个消费者忙的不可开交。**没有充分利用每一个消费者的能力,最终消息处理的耗时远远超过了1秒。这样显然是有问题的。

5)能者多劳
在spring中有一个简单的配置,可以解决这个问题。我们修改consumer服务的application.yml文件,添加配置:

spring:rabbitmq:listener:simple:prefetch: 1 # 每次只能获取一条消息,处理完成才能获取下一个消息

在配置中,prefetch: 1表示每个消费者每次只能从队列中预取1个消息,消费完就能拿下一次,不需要等轮询(RabbitMQ默认是轮询)。它可以帮助保证每个消息在被消费者处理时都能得到较为均匀的分配,避免某个消费者处理速度慢而导致其他消费者空闲的情况。如果不配置的话,那么RabbitMQ采用的就是一个公平轮询的方式,将消息依次发给一个消费,等他消费完了再发下一个给另外的消费者

二、交换机类型

之前的WorkQueues模型并没有交换机,引入交换机后,消息发送和接收的模式就会有很大的变化,模型如下所示
在这里插入图片描述

  • Publisher:生产者,不再发送消息到队列中,而是发给交换机

  • Exchange:交换机,一方面,接收生产者发送的消息。另一方面,知道如何处理消息,例如递交给某个特别队列、递交给所有队列、或是将消息丢弃。到底如何操作,取决于Exchange选的类型。

  • Queue:消息队列,接收消息、缓存消息。不过队列一定要与交换机绑定。

  • Consumer:消费者,订阅队列。

1、Fanout交换机

Fanout,在MQ中叫广播,在广播的模式下,消息发送的流程如下图所示

在这里插入图片描述
其主要特点:

1) 可以有多个队列

2) 每个队列都可以绑定到Exchange(交换机)

3) 生产者发送的消息,只能发送到交换机

4) 交换机把消息发送给绑定过的所有队列

5) 订阅队列的消费者都能拿到消息

案例演示
1)声明交换机和对应的队列,并进行绑定

    /*** 声明交换机*/@Beanpublic FanoutExchange fanoutExchange(){return new FanoutExchange("xuyuan.fanout");}/*** 第1个队列*/@Beanpublic Queue fanoutQueue1(){return new Queue("fanout.queue1");}/*** 第2个队列*/@Beanpublic Queue fanoutQueue2(){return new Queue("fanout.queue2");}
/*** 绑定队列和交换机*/@Beanpublic Binding bindingQueue1(Queue fanoutQueue1, FanoutExchange fanoutExchange){return BindingBuilder.bind(fanoutQueue1).to(fanoutExchange);}/*** 绑定队列和交换机*/@Beanpublic Binding bindingQueue2(Queue fanoutQueue2, FanoutExchange fanoutExchange){return BindingBuilder.bind(fanoutQueue2).to(fanoutExchange);}

2)生产者发送消息

@Test
public void testFanoutExchange() {// 交换机名称String exchangeName = "xuyuan.fanout";// 消息String message = "hello, xuyuan ,nihao!";rabbitTemplate.convertAndSend(exchangeName, "", message);
}

3)消费者接收消息

@RabbitListener(queues = "fanout.queue1")
public void listenFanoutQueue1(String msg) {System.out.println("消费者1接收到Fanout消息:【" + msg + "】");
}@RabbitListener(queues = "fanout.queue2")
public void listenFanoutQueue2(String msg) {System.out.println("消费者2接收到Fanout消息:【" + msg + "】");
}

分析总结:
交换机的作用主要是:

  • 接收对应Publisher发送的消息
  • 将消息按照规则路由道与之绑定的队列
  • 不能缓存消息,路由失败,消息丢失
  • FanoutExchange会将消息路由到每个绑定的队列。
2、Direct交换机

场景:在Fanout模式中,一条消息,会被所有订阅的队列都消费。但是,在某些场景下,我们希望不同的消息被不同的队列消费。这时就要用到Direct类型的Exchange。
在这里插入图片描述
在Direct模型下:

  • 队列与交换机的绑定,不能是任意绑定的,需要指定一个Routingkey(路由key)
  • 消息的发送方在向Exchange发送消息时,也必须指定消息的RoutingKey。
  • Exchange不在把消息发送给每一个绑定的队列,而是根据消息的RoutingKey来发送到指定的队列中去。然后消费者监听对应的队列得到消息。

案例如下:

@Configuration
public class DirectConfig {/*** 声明交换机* @return Direct类型交换机*/@Beanpublic DirectExchange directExchange(){return ExchangeBuilder.directExchange("hmall.direct").build();}/*** 第1个队列*/@Beanpublic Queue directQueue1(){return new Queue("direct.queue1");}/*** 绑定队列和交换机*/@Beanpublic Binding bindingQueue1WithRed(Queue directQueue1, DirectExchange directExchange){return BindingBuilder.bind(directQueue1).to(directExchange).with("red");}/*** 绑定队列和交换机*/@Beanpublic Binding bindingQueue1WithBlue(Queue directQueue1, DirectExchange directExchange){return BindingBuilder.bind(directQueue1).to(directExchange).with("blue");}/*** 第2个队列*/@Beanpublic Queue directQueue2(){return new Queue("direct.queue2");}/*** 绑定队列和交换机*/@Beanpublic Binding bindingQueue2WithRed(Queue directQueue2, DirectExchange directExchange){return BindingBuilder.bind(directQueue2).to(directExchange).with("red");}/*** 绑定队列和交换机*/@Beanpublic Binding bindingQueue2WithYellow(Queue directQueue2, DirectExchange directExchange){return BindingBuilder.bind(directQueue2).to(directExchange).with("yellow");}
}
3、Topic交换机

分析:

使用Direct可以根据对应的RoutingKey路由到指定的队列,但是对于多元组就比较麻烦,只能一个一个绑定对应的RoutingKey,此时Topic交换机就派上用场了,可以同时划分一个子组,一个消息可以根据一个组别的队列进行投递,就需要用到Topic交换机
Topic类型Exchange可以让队列在绑定BindingKey 的时候使用通配符!

BindingKey 一般都是有一个或多个单词组成,多个单词之间以“ .”分割,例如: item.insert

通配符规则:

#:匹配一个或多个词

*:只匹配1个词

举例子:

  • xuyuan.# :它能够匹配xuyuan.com 或者xuyuan.xxx.xx等等
    xuyuan.* :只能匹配xuyuan.aa 或者xuyuan.xx

在这里插入图片描述
1)初始化

@Configuration
public class Topic {/*** 声明交换机* @return Topic类型交换机*/@Beanpublic TopicExchange topicExchange(){return ExchangeBuilder.topicExchange("xuyuan.topic").build();}/*** 第1个队列*/@Beanpublic Queue topicQueue1(){return new Queue("topic.queue1");}/*** 绑定队列和交换机*/@Beanpublic Binding bindingQueue1WithRed(Queue topicQueue1, TopicExchange topicExchange){return BindingBuilder.bind(topicQueue1).to(topicExchange).with("xuyuan.new");}/*** 绑定队列和交换机*/@Beanpublic Binding bindingQueue1WithBlue(Queue topicQueue1, TopicExchange topicExchange){return BindingBuilder.bind(topicQueue1).to(topicExchange).with("xuyuan.#");}/*** 第2个队列*/@Beanpublic Queue topicQueue2(){return new Queue("topic.queue2");}/*** 绑定队列和交换机*/@Beanpublic Binding bindingQueue2WithRed(Queue topicQueue2, TopicExchange topicExchange){return BindingBuilder.bind(topicQueue2).to(topicExchange).with("ooyl.*");}/*** 绑定队列和交换机*/@Beanpublic Binding bindingQueue2WithYellow(Queue topicQueue2, TopicExchange topicExchange){return BindingBuilder.bind(topicQueue2).to(topicExchange).with("ooyl.#");}
}

2)消息发送

/*** topicExchange*/
@Test
public void testSendTopicExchange() {// 交换机名称String exchangeName = "hmall.topic";// 消息String message = "许苑2上某个人";// 发送消息rabbitTemplate.convertAndSend(exchangeName, "xuyuan.news", message);
}

3)消息接收

@RabbitListener(queues = "topic.queue1")
public void listenTopicQueue1(String msg){System.out.println("消费者1接收到topic.queue1的消息:【" + msg + "】");
}@RabbitListener(queues = "topic.queue2")
public void listenTopicQueue2(String msg){System.out.println("消费者2接收到topic.queue2的消息:【" + msg + "】");
}

总结
下Direct交换机与Topic交换机的差异如下:

Topic交换机接收的消息RoutingKey必须是多个单词,以 . 分割

Topic交换机与队列绑定时的bindingKey可以指定通配符

#:代表0个或多个词

*:代表1个词

三、基于注解声明

基于@Bean的方式声明队列和交换机比较麻烦,Spring还提供了基于注解方式来声明。

例如,我们同样声明Direct模式的交换机和队列:

@RabbitListener(bindings = @QueueBinding(value = @Queue(name = "direct.queue1"),exchange = @Exchange(name = "hmall.direct", type = ExchangeTypes.DIRECT),key = {"red", "blue"}
))
public void listenDirectQueue1(String msg){System.out.println("消费者1接收到direct.queue1的消息:【" + msg + "】");
}@RabbitListener(bindings = @QueueBinding(value = @Queue(name = "direct.queue2"),exchange = @Exchange(name = "hmall.direct", type = ExchangeTypes.DIRECT),key = {"red", "yellow"}
))
public void listenDirectQueue2(String msg){System.out.println("消费者2接收到direct.queue2的消息:【" + msg + "】");
}

是不是简单多了。 再试试Topic模式:

@RabbitListener(bindings = @QueueBinding(value = @Queue(name = "topic.queue1"),exchange = @Exchange(name = "hmall.topic", type = ExchangeTypes.TOPIC),key = "china.#"
))
public void listenTopicQueue1(String msg){System.out.println("消费者1接收到topic.queue1的消息:【" + msg + "】");
}@RabbitListener(bindings = @QueueBinding(value = @Queue(name = "topic.queue2"),exchange = @Exchange(name = "hmall.topic", type = ExchangeTypes.TOPIC),key = "#.news"
))
public void listenTopicQueue2(String msg){System.out.println("消费者2接收到topic.queue2的消息:【" + msg + "】");
}

相关文章:

全网最详细RabbitMQ教学包括如何安装环境【RabbitMQ】RabbitMQ + Spring Boot集成零基础入门(基础篇)

目录 一、初始Rabbitmq1、什么是Rabbitmq&#xff0c;它的概述是什么&#xff1f;2、RabbitMQ的应用场景3、RabbitMQ主要组件4、RabbitMQ 的优点5、与其他消息队列性能比较 二、RabbitMQ环境安装初始化三、SpringAMQPRabbitMQ实战入门&#xff08;基本API&#xff09;1、实战入…...

esp32记录一次错误

报错信息 PS C:\XingNian\GeRen\4Gdownload\wireless-esp8266-dap> idf.py build Executing action: all (aliases: build) Running cmake in directory c:\xingnian\geren\4gdownload\wireless-esp8266-dap\build Executing "cmake -G Ninja -DPYTHON_DEPS_CHECKED1 …...

Moonshine - 新型开源ASR(语音识别)模型,体积小,速度快,比OpenAI Whisper快五倍 本地一键整合包下载

Moonshine 是由 Useful Sensors 公司推出的一系列「语音到文本&#xff08;speech-to-text, STT&#xff09;转换模型」&#xff0c;旨在为资源受限设备提供快速而准确的「自动语音识别&#xff08;ASR&#xff09;服务」。Moonshine 的设计特别适合于需要即时响应的应用场景&a…...

java-web-苍穹外卖-day1:软件开发步骤简化版+后端环境搭建

软件开发 感觉书本上和线上课程, 讲的太抽象, 不好理解, 但软件开发不就是为了开发应用程序吗?! 干嘛搞这么抽象,对吧, 下面个人对于软件开发的看法, 主打简单易懂, 当然,我一IT界小菜鸟, 对软件开发的认识也很浅显, 这个思维导图也仅仅是现阶段我的看法, 我以后会尽力…...

一个国产 API 开源项目,在 ProductHunt 杀疯了...

随着AI 大模型技术的兴起&#xff0c;全球产品更新和面市进程速度肉眼可见的加快&#xff0c;Product Hunt 作为全球知名的产品发现平台&#xff0c;每日都会精选出一系列产品能力强劲的新产品&#xff0c;这些产品不仅代表了技术前沿&#xff0c;还反映了市场的发展趋势。 上…...

斗破QT编程入门系列之二:认识Qt:编写一个HelloWorld程序(四星斗师)

斗破Qt目录&#xff1a; 斗破Qt编程入门系列之前言&#xff1a;认识Qt&#xff1a;Qt的获取与安装&#xff08;四星斗师&#xff09; 斗破QT编程入门系列之一&#xff1a;认识Qt&#xff1a;初步使用&#xff08;四星斗师&#xff09; 斗破QT编程入门系列之二&#xff1a;认识…...

木马病毒相关知识

1、 木马的定义 相当于一个远控程序&#xff08;一个控制端[hack]、一个被控端[受害端]&#xff09; 在计算机系统中&#xff0c;“特洛伊木马”指系统中被植入的、人为设计的程序&#xff0c;目的包括通过网终远程控制其他用户的计算机系统&#xff0c;窃取信息资料&#xff0…...

用 Python 写了一个天天酷跑(附源码)

Hello&#xff0c;大家好&#xff0c;给大家说一下&#xff0c;我要开始装逼了 这期写个天天酷跑玩一下叭&#xff01; 制作一个完整的“天天酷跑”游戏涉及很多方面&#xff0c;包括图形渲染、物理引擎、用户输入处理、游戏逻辑等。由于Python是一种高级编程语言&#xff0c;…...

【网络-交换机】生成树协议、环路检测

路由优先级 路由优先级决定了在多种可达的路由类型中&#xff0c;哪种路由将被用来转发数据包。路由优先级值越低&#xff0c;对应路由的优先级越高&#xff0c;优先级值255表示对应的路由不可达。一般情况下&#xff0c;静态路由的优先级为1&#xff0c;OSPF路由优先级为110&a…...

C++ 中的 JSON 序列化和反序列化:结构体与枚举类型的处理

在 C 编程中&#xff0c;处理 JSON 数据是一项常见任务&#xff0c;特别是在需要与其他系统或前端进行数据交换时。nlohmann::json 库是一个功能强大且易于使用的 JSON 库&#xff0c;它允许我们轻松地在 C 中进行 JSON 数据的序列化和反序列化。本文将详细介绍如何使用 nlohma…...

MySQL 批量删除海量数据的几种方法

目录 一、问题分析 二、批量删除海量数据的几种方法 方法 1&#xff1a;使用 LIMIT 分批删除 方法 2&#xff1a;通过主键范围分批删除 方法 3&#xff1a;通过自定义批量删除存储过程 方法 4&#xff1a;创建临时表替换旧表 三、性能优化建议 总结 在数据库的日常维护…...

【docker入门】docker的安装

目录 Centos 7 添加docker 官方仓库到yum源 将 Docker 的官方镜像源替换为国内可以的 Docker 镜像源 安装docker 配置docker加速源 Ubuntu 创建 gpg key 目录 下载 gpg key 添加国内可用镜像源到 系统的 APT 仓库中 安装docker 配置加速源 Centos 7 添加docker 官方仓…...

单例模式五种写法

饿汉式&#xff08;线程安全&#xff09; public class Singleton {// 直接创建实例&#xff0c;在类加载时就完成实例化private static final Singleton instance new Singleton();// 私有构造函数private Singleton() {}// 提供公共的静态方法获取实例public static Single…...

解析静态链接

文章目录 静态链接空间与地址分配相似段合并虚拟地址分配符号地址确定 符号解析与重定位链接器优化重复代码消除函数链接级别 静态库静态链接优缺点 静态链接 一组目标文件经过链接器链接后形成的文件即可执行文件&#xff0c;如果没有动态库的加入&#xff0c;那么这个可执行…...

前端基础-html-注册界面

&#xff08;200粉啦&#xff0c;感谢大家的关注~ 一起加油吧~&#xff09; 浅浅分享下作业&#xff0c;大佬轻喷~ 网页最终效果&#xff1a; 详细代码&#xff1a; ​ <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"…...

量子电路的实现 基于ibm的qiskit

量子计算的物理实现 量子计算的实现有几种方式&#xff0c;最常用的就是超导量子计算机&#xff0c;它的量子处理器是用超导传输量子比特构建的&#xff0c;它是由一个约瑟夫森结和一个并联的电容器组成的电路。约瑟夫森结是一种非线性电感&#xff0c;由两层重叠的超导…...

关于谷歌浏览器debug模式不进断点问题解决方案

第一步.浏览器F12弹出调试者模式 第二步.点击设置齿轮&#xff0c;找到Ignore List,将node_model取消勾选&#xff0c;关闭浏览器&#xff0c;重新打开就进断点了...

制造行业实践|悠进电装基于超融合完成信息化改造, 保障业务系统 7/24 长跑

当一辆汽车在路上奔驰时&#xff0c;确保车内各种电气信号正常传递和电力供给的关键是什么&#xff1f;正是那不起眼却功不可没的汽车线束。这些精密编织的电线网络&#xff0c;犹如汽车的“神经网络”和“动脉血管”&#xff0c;在传递电气信号、数据的同时&#xff0c;源源不…...

如何学习C++游戏开发

学习C游戏开发是一个涉及多个领域的复杂过程&#xff0c;包括编程、游戏设计、图形学等。 1. **学习C基础**&#xff1a; - 掌握C的基本语法和面向对象编程。 - 学习C标准库&#xff0c;特别是STL&#xff08;标准模板库&#xff09;。 2. **理解游戏开发概念**&#xf…...

计算网络信号

题目描述&#xff1a; 网络信号经过传递会逐层衰减&#xff0c;且遇到阻隔物无法直接穿透&#xff0c;在此情况下需要计算某个位置的网络信号值。注意&#xff1a;网络信号可以绕过阻隔物 array[m][n]的二维数组代表网格地图&#xff0c; array[i][j]0代表i行j列是空旷位置&…...

MongoDB学习和应用(高效的非关系型数据库)

一丶 MongoDB简介 对于社交类软件的功能&#xff0c;我们需要对它的功能特点进行分析&#xff1a; 数据量会随着用户数增大而增大读多写少价值较低非好友看不到其动态信息地理位置的查询… 针对以上特点进行分析各大存储工具&#xff1a; mysql&#xff1a;关系型数据库&am…...

【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)

🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...

leetcodeSQL解题:3564. 季节性销售分析

leetcodeSQL解题&#xff1a;3564. 季节性销售分析 题目&#xff1a; 表&#xff1a;sales ---------------------- | Column Name | Type | ---------------------- | sale_id | int | | product_id | int | | sale_date | date | | quantity | int | | price | decimal | -…...

处理vxe-table 表尾数据是单独一个接口,表格tableData数据更新后,需要点击两下,表尾才是正确的

修改bug思路&#xff1a; 分别把 tabledata 和 表尾相关数据 console.log() 发现 更新数据先后顺序不对 settimeout延迟查询表格接口 ——测试可行 升级↑&#xff1a;async await 等接口返回后再开始下一个接口查询 ________________________________________________________…...

力扣热题100 k个一组反转链表题解

题目: 代码: func reverseKGroup(head *ListNode, k int) *ListNode {cur : headfor i : 0; i < k; i {if cur nil {return head}cur cur.Next}newHead : reverse(head, cur)head.Next reverseKGroup(cur, k)return newHead }func reverse(start, end *ListNode) *ListN…...

【JavaSE】多线程基础学习笔记

多线程基础 -线程相关概念 程序&#xff08;Program&#xff09; 是为完成特定任务、用某种语言编写的一组指令的集合简单的说:就是我们写的代码 进程 进程是指运行中的程序&#xff0c;比如我们使用QQ&#xff0c;就启动了一个进程&#xff0c;操作系统就会为该进程分配内存…...

Redis:现代应用开发的高效内存数据存储利器

一、Redis的起源与发展 Redis最初由意大利程序员Salvatore Sanfilippo在2009年开发&#xff0c;其初衷是为了满足他自己的一个项目需求&#xff0c;即需要一个高性能的键值存储系统来解决传统数据库在高并发场景下的性能瓶颈。随着项目的开源&#xff0c;Redis凭借其简单易用、…...

FFmpeg:Windows系统小白安装及其使用

一、安装 1.访问官网 Download FFmpeg 2.点击版本目录 3.选择版本点击安装 注意这里选择的是【release buids】&#xff0c;注意左上角标题 例如我安装在目录 F:\FFmpeg 4.解压 5.添加环境变量 把你解压后的bin目录&#xff08;即exe所在文件夹&#xff09;加入系统变量…...

群晖NAS如何在虚拟机创建飞牛NAS

套件中心下载安装Virtual Machine Manager 创建虚拟机 配置虚拟机 飞牛官网下载 https://iso.liveupdate.fnnas.com/x86_64/trim/fnos-0.9.2-863.iso 群晖NAS如何在虚拟机创建飞牛NAS - 个人信息分享...

Spring Boot + MyBatis 集成支付宝支付流程

Spring Boot MyBatis 集成支付宝支付流程 核心流程 商户系统生成订单调用支付宝创建预支付订单用户跳转支付宝完成支付支付宝异步通知支付结果商户处理支付结果更新订单状态支付宝同步跳转回商户页面 代码实现示例&#xff08;电脑网站支付&#xff09; 1. 添加依赖 <!…...