9. RabbitMQ 消息队列幂等性,优先级队列,惰性队列的详细说明
9. RabbitMQ 消息队列幂等性,优先级队列,惰性队列的详细说明
文章目录
- 9. RabbitMQ 消息队列幂等性,优先级队列,惰性队列的详细说明
- 1. RabbitMQ 消息队列的 “ 幂等性 ” 的问题
- 1.1 RabbitMQ 消息队列的“幂等性”的概念
- 2. RabbitMQ 消息队列的 “ 优先级队列 ” 的问题
- 2.1 创建交换机
- 2.2 创建队列
- 2.3 队列绑定交换机
- 2.4 RabbitMQ 结合 Spring Boot (分模块微服务)实现 “优先级队列”
- 3. RabbitMQ 消息队列的 “ 惰性队列 ” 的问题
- 3.1 RabbitMQ 消息队列 “ 惰性队列 ”的概念
- 3.2 基于策略方式设定
- 3.3 在声明队列时使用参数设定
- 3.4 实操演练
- 4. 最后:
1. RabbitMQ 消息队列的 “ 幂等性 ” 的问题
1.1 RabbitMQ 消息队列的“幂等性”的概念
用户对于同一操作发起的一次请求或者多次请求的结果是一致的,不会因为多次点击而产生了副作用。举个最简单的例子:那就是支付,用户购买商品后支付,支付扣款成功,但是返回结果的时候网络异常,此时钱已经扣了,用户再次点击按钮,此时会进行第二次扣款,返回结果成功,用户查询余额发现多扣钱了,流水记录也变成了两条。在以前的单应用系统中,我们只需要把数据操作放入到事务中即可,发生错误立即回滚,但是再响应客户端的时候也有可能出现网络中断或者异常等等。
消息消费时的幂等性(消息不被重复消费)
同一个消息,第一次接收,正常处理业务,如果该消息第二次再接收,那就不能再处理业务,否则就处理重复了;
**幂等性是:**对于一个资源,不管你请求一次还是请求多次,对该资源本身造成的影响应该是相同的,不能因为重复的请求而对该资源重复造成影响;
以接口幂等性举例:
接口幂等性是指: 一个接口用同样的参数反复调用,不会造成业务错误,那么这个接口就是具有幂等性的;
注册接口;
发送短信验证码接口; 比如同一个订单我支付两次,但是只会扣款一次,第二次支付不会扣款,这说明这个支付接口是具有幂等性的;
如何避免消息的重复消费问题?(消息消费时的幂等性)
全局唯一 ID + Redis
生产者在发送消息时,为每条消息设置一个全局唯一的
messageId
,消费者拿到消息后,使用setnx
命令,将messageId
作为key
放到Redis
中:setnx(messageId, 1)
;
- 若返回1,说明之前没有消费过,正常消费;
- 若返回0,说明这条消息之前已消费过,抛弃;
这里是利用 Redis 的一个 setnx 不可重复,原子性的特征。
消息重复消费
消费者在消费 MQ 中的消息时,MQ 已把消息发送给消费者,消费者在给 MQ 返回 ack 时网络中断, 故 MQ 未收到确认信息,该条消息会重新发给其他的消费者,或者在网络重连后再次发送给该消费者,但 实际上该消费者已成功消费了该条消息,造成消费者消费了重复的消息。
解决思路
MQ 消费者的幂等性的解决一般使用全局 ID 或者写个唯一标识比如时间戳 或者 UUID 或者订单消费 者消费 MQ 中的消息也可利用 MQ 的该 id 来判断,或者可按自己的规则生成一个全局唯一 id,每次消费消 息时用该 id 先判断该消息是否已消费过。
消费端的幂等性保障
在海量订单生成的业务高峰期,生产端有可能就会重复发生了消息,这时候消费端就要实现幂等性, 这就意味着我们的消息永远不会被消费多次,即使我们收到了一样的消息。业界主流的幂等性有两种操作:
- a. 唯一 ID+指纹码机制, 利用数据库主键去重
- b.利用 redis 的原子性去实现
唯一 ID+指纹码机制
指纹码: 我们的一些规则或者时间戳加别的服务给到的唯一信息码,它并不一定是我们系统生成的,基 本都是由我们的业务规则拼接而来,但是一定要保证唯一性,然后就利用查询语句进行判断这个 id 是否存 在数据库中,优势就是实现简单就一个拼接,然后查询判断是否重复;劣势就是在高并发时,如果是单个数 据库就会有写入性能瓶颈当然也可以采用分库分表提升性能,但也不是我们最推荐的方式。
Redis 原子性
关于 Redis 的内容,感兴趣的大家可以移步至:✏️✏️✏️ Redis_ChinaRainbowSea的博客-CSDN博客
利用 redis 执行 setnx 命令,天然具有幂等性。从而实现不重复消费
2. RabbitMQ 消息队列的 “ 优先级队列 ” 的问题
在我们系统中有一个订单催付 的场景,我们的客户在天猫下的订单,淘宝会及时将订单推送给我们,如果在用户设定的时间内未付款那么就会给用户推送一条短信提醒,很简单的一个功能对吧,但是 , tmall 商家对我们来说,肯定是要分为大客户 和小客户 的对吧,比如像苹果,小米这样大商家一年起码能给我们创造很大的利润,所以理应当然,它们的订单必须得到优先处理,而曾经我们的后端系统是使用 Redis 来存放的定时轮询,大家都知道 Redis 只能用 List 做一个简简单单的消息队列,并不能实现一个优先级的场景,所以订单量大了后采用 RabbitMQ 进行改造和优化,如果发现是大客户的订单给一个相对比较高的优先级,否则就是默认的优先级。
如何添加:
- 控制台页面添加
- 队列代码中添加优先级
Map<String, Object> params = new HashMap();
params.put("x-max-priority", 10);
channel.queueDeclare("hello", true, false, false, params);
- 消息中代码添加优先级
AMQP.BasicProperties properties = new AMQP.BasicProperties().builder().priority(5).build();
- 注意事项:
要让队列实现优先级需要做的事情有如下事情:队列需要设置为优先级队列,消息需要设置消息的优先级,消费者需要等待消息已经发送到队列中才去消费,因为:这样才有机会对消息进行排序
简单的来说就是:我们需要让生产者(含有优先级)发送的消息,必须让其存放在队列当中,并且要是到达一定的量,让其在队列当中进行可以有一个时间进行一个(根据优先级上进行一个排序),不然,如果只有一个,就不需要将队列进行排序,因为只有一个就不存在一个优先级的问题。只有存在多个的时候,这样才有机会对消息进行一个排序。
实战:消息队列的“优先级队列” 的具体代码实现:
- 生产者——发送消息
package com.rainbowsea.rabbitmq.nine;import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rainbowsea.rabbitmq.utils.RabbitMQUtils;public class Producer {private static final String QUEUE_NAME = "hello";public static void main(String[] args) throws Exception {try (Channel channel = RabbitMQUtils.getChannel();) {
//给消息赋予一个 priority 属性AMQP.BasicProperties properties = new AMQP.BasicProperties().builder().priority(5).build();for (int i = 1; i < 11; i++) {String message = "info" + i;if (i == 5) {channel.basicPublish("", QUEUE_NAME, properties, message.getBytes());} else {channel.basicPublish("", QUEUE_NAME, null, message.getBytes());}System.out.println("发送消息完成:" + message);}}}
}
- 消费者——消费
package com.rainbowsea.rabbitmq.nine;import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.DeliverCallback;
import com.rainbowsea.rabbitmq.utils.RabbitMQUtils;import java.util.HashMap;
import java.util.Map;public class Consumer {private static final String QUEUE_NAME = "hello";public static void main(String[] args) throws Exception {Channel channel = RabbitMQUtils.getChannel();
//设置队列的最大优先级 最大可以设置到 255 官网推荐 1-10 如果设置太高比较吃内存和 CPU Map<String, Object> params = new HashMap();params.put("x-max-priority", 10);channel.queueDeclare(QUEUE_NAME, true, false, false, params);System.out.println("消费者启动等待消费......");DeliverCallback deliverCallback = (consumerTag, delivery) -> {String receivedMessage = new String(delivery.getBody());System.out.println("接收到消息:" + receivedMessage);};channel.basicConsume(QUEUE_NAME, true, deliverCallback, (consumerTag) -> {System.out.println("消费者无法消费消息时调用,如队列被删除");});}
}
2.1 创建交换机
exchange.test.priority
2.2 创建队列
queue.test.priority
x-max-priority
2.3 队列绑定交换机
2.4 RabbitMQ 结合 Spring Boot (分模块微服务)实现 “优先级队列”
生产者发送消息
1. 配置POM
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.1.5</version>
</parent><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency>
</dependencies>
2. 配置 YAML 也可以使用 properties
spring:rabbitmq:host: 192.168.200.100port: 5672username: guestpassword: 123456virtual-host: /
3. 主启动类
package com.rainbowsea.mq;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class RabbitMQPriorityProducer {public static void main(String[] args) {SpringApplication.run(RabbitMQPriorityProducer.class, args);}}
4. 发送消息
- 不要启动消费者程序,让多条不同优先级的消息滞留在队列中
- 第一次发送优先级为1的消息
- 第二次发送优先级为2的消息
- 第三次发送优先级为3的消息
- 先发送的消息优先级低,后发送的消息优先级高,将来看看消费端是不是先收到优先级高的消息
第一次发送优先级为1的消息
package com.rainbowsea.mq.test;import jakarta.annotation.Resource;
import org.junit.jupiter.api.Test;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.boot.test.context.SpringBootTest;@SpringBootTest
public class RabbitMQTest {public static final String EXCHANGE_PRIORITY = "exchange.test.priority";public static final String ROUTING_KEY_PRIORITY = "routing.key.test.priority";@Resourceprivate RabbitTemplate rabbitTemplate;@Testpublic void testSendMessage() {rabbitTemplate.convertAndSend(EXCHANGE_PRIORITY, ROUTING_KEY_PRIORITY, "I am a message with priority 1.", message->{message.getMessageProperties().setPriority(1);return message;});}}
第二次发送优先级为2的消息
@Test
public void testSendMessage() {rabbitTemplate.convertAndSend(EXCHANGE_PRIORITY, ROUTING_KEY_PRIORITY, "I am a message with priority 2.", message->{message.getMessageProperties().setPriority(2);return message;});
}
第三次发送优先级为3的消息
@Test
public void testSendMessage() {rabbitTemplate.convertAndSend(EXCHANGE_PRIORITY, ROUTING_KEY_PRIORITY, "I am a message with priority 3.", message->{message.getMessageProperties().setPriority(3);return message;});
}
消费端接收消息:
- 配置POM
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.1.5</version>
</parent><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency>
</dependencies>
- 配置YAML
spring:rabbitmq:host: 192.168.200.100port: 5672username: guestpassword: 123456virtual-host: /
3. 主启动类
package com.rainbowsea.mq;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class RabbitMQPriorityConsumer {public static void main(String[] args) {SpringApplication.run(RabbitMQPriorityConsumer.class, args);}}
4.监听器
package com.rainbowsea.mq.listener;import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.*;
import org.springframework.stereotype.Component;@Slf4j
@Component
public class MyMessageProcessor {public static final String QUEUE_PRIORITY = "queue.test.priority";@RabbitListener(queues = {QUEUE_PRIORITY})public void processPriorityMessage(String data, Message message, Channel channel) throws IOException {log.info(data);channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);}}
5. 测试效果
对于已经滞留服务器的消息,只要消费端一启动,就能够收到消息队列的投递,打印效果如下:
3. RabbitMQ 消息队列的 “ 惰性队列 ” 的问题
3.1 RabbitMQ 消息队列 “ 惰性队列 ”的概念
“惰性队列” 的应用场景:
RabbitMQ 从 3.6.0 版本开始引入了惰性队列的概念。惰性队列会尽可能的将消息存入磁盘中,而在消 费者消费到相应的消息时才会被加载到内存中,它的一个重要的设计目标是能够支持更长的队列,即支持 更多的消息存储。当消费者由于各种各样的原因(比如消费者下线、宕机亦或者是由于维护而关闭等)而致 使长时间内不能消费消息造成堆积时,惰性队列就很有必要了。
默认情况下,当生产者将消息发送到 RabbitMQ 的时候,队列中的消息会尽可能的存储在内存之中, 这样可以更加快速的将消息发送给消费者。即使是持久化的消息,在被写入磁盘的同时也会在内存中驻留 一份备份。当 RabbitMQ 需要释放内存的时候,会将内存中的消息换页至磁盘中,这个操作会耗费较长的 时间,也会阻塞队列的操作,进而无法接收新的消息。虽然 RabbitMQ 的开发者们一直在升级相关的算法, 但是效果始终不太理想,尤其是在消息量特别大的时候。
官网说明
队列可以创建为默认
或惰性
模式,模式指定方式是:
- 使用队列策略(建议)
- 设置
queue.declare
参数
如果策略和队列参数同时指定,那么队列参数有更高优先级。如果队列模式是在声明时通过可选参数指定的,那么只能通过删除队列再重新创建来修改。
3.2 基于策略方式设定
# 登录Docker容器
docker exec -it rabbitmq /bin/bash# 运行rabbitmqctl命令
rabbitmqctl set_policy Lazy "^lazy-queue$" '{"queue-mode":"lazy"}' --apply-to queues
命令解读:
-
rabbitmqctl
命令所在目录是:/opt/rabbitmq/sbin
,该目录已配置到Path环境变量 -
set_policy
是子命令,表示设置策略 -
Lazy
是当前要设置的策略名称,是我们自己自定义的,不是系统定义的 -
"^lazy-queue$"
是用正则表达式限定的队列名称,凡是名称符合这个正则表达式的队列都会应用这里的设置 -
'{"queue-mode":"lazy"}'
是一个JSON格式的参数设置指定了队列的模式为"lazy" -
–-apply-to参数指定该策略将应用于队列(queues)级别
-
命令执行后,所有名称符合正则表达式的队列都会应用指定策略,包括未来新创建的队列
如果需要修改队列模式可以执行如下命令(不必删除队列再重建):
rabbitmqctl set_policy Lazy "^lazy-queue$" '{"queue-mode":"default"}' --apply-to queues
3.3 在声明队列时使用参数设定
- 参数名称:x-queue-mode
- 可用参数值:
- default
- lazy
- 不设置就是取值为default
Java代码原生API设置方式:
Map<String, Object> args = new HashMap<String, Object>();
args.put("x-queue-mode", "lazy");
channel.queueDeclare("myqueue", false, false, false, args);
Java代码注解设置方式:
@Queue(value = QUEUE_NAME, durable = "true", autoDelete = "false", arguments = {@Argument(name = "x-queue-mode", value = "lazy")
})
队列具备两种模式:default 和 lazy。默认的为 default 模式,在 3.6.0 之前的版本无需做任何变更。lazy 模式即为惰性队列的模式,可以通过调用
channel.queueDeclare
方法的时候在参数中设置,也可以通过 Policy 的方式设置,如果一个队列同时使用这两种方式设置的话,那么 Policy 的方式具备更高的优先级。 如果要通过声明的方式改变已有队列的模式的话,那么只能先删除队列,然后再重新声明一个新的。
在队列声明的时候可以通过“x-queue-mode”
参数来设置队列的模式,取值为“default”
和“lazy”
。下面示 例中演示了一个惰性队列的声明细节:Map<String, Object> args = new HashMap<String, Object>(); args.put("x-queue-mode", "lazy"); channel.queueDeclare("myqueue", false, false, false, args);
内存开销对比:
在发送 1 百万条消息,每条消息大概占 1KB 的情况下,普通队列占用内存是 1.2GB,而惰性队列仅仅占用 1.5MB
3.4 实操演练
生产者端代码
配置POM
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.1.5</version></parent><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency></dependencies>
配置YAML
spring:rabbitmq:host: 192.168.200.100port: 5672username: guestpassword: 123456virtual-host: /
主启动类
package com.rainbowsea.mq;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class RabbitMQLazyProducer {public static void main(String[] args) {SpringApplication.run(RabbitMQLazyProducer.class, args);}}
发送消息
package com.rainbowsea.mq.test;import jakarta.annotation.Resource;
import org.junit.jupiter.api.Test;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.boot.test.context.SpringBootTest;@SpringBootTest
public class RabbitMQTest {public static final String EXCHANGE_LAZY_NAME = "exchange.rainbowsea.lazy";public static final String ROUTING_LAZY_KEY = "routing.key.rainbowsea.lazy";@Resourceprivate RabbitTemplate rabbitTemplate;@Testpublic void testSendMessage() {rabbitTemplate.convertAndSend(EXCHANGE_LAZY_NAME, ROUTING_LAZY_KEY, "I am a message for test lazy queue.");}}
消费者端代码
配置POM
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.1.5</version></parent><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency></dependencies>
配置YAML
spring:rabbitmq:host: 192.168.200.100port: 5672username: guestpassword: 123456virtual-host: /
主启动类
package com.rainbowsea.mq;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class RabbitMQLazyConsumerMainType {public static void main(String[] args) {SpringApplication.run(RabbitMQLazyConsumerMainType.class, args);}}
监听器
package com.rainbowsea.mq.listener;import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.*;
import org.springframework.stereotype.Component;@Component
@Slf4j
public class MyLazyMessageProcessor {public static final String EXCHANGE_LAZY_NAME = "exchange.rainbowsea.lazy";public static final String ROUTING_LAZY_KEY = "routing.key.rainbowsea.lazy";public static final String QUEUE_LAZY_NAME = "queue.rainbowsea.lazy";@RabbitListener(bindings = @QueueBinding(value = @Queue(value = QUEUE_LAZY_NAME, durable = "true", autoDelete = "false", arguments = {@Argument(name = "x-queue-mode", value = "lazy")}),exchange = @Exchange(value = EXCHANGE_LAZY_NAME, durable = "true", autoDelete = "false"),key = {ROUTING_LAZY_KEY}))public void processMessageLazy(String data, Message message, Channel channel) {log.info("消费端接收到消息:" + data);}}
测试:
-
先启动消费端
-
基于消费端@RabbitListener注解中的配置,自动创建了队列
- 发送消息
4. 最后:
“在这个最后的篇章中,我要表达我对每一位读者的感激之情。你们的关注和回复是我创作的动力源泉,我从你们身上吸取了无尽的灵感与勇气。我会将你们的鼓励留在心底,继续在其他的领域奋斗。感谢你们,我们总会在某个时刻再次相遇。”
相关文章:
9. RabbitMQ 消息队列幂等性,优先级队列,惰性队列的详细说明
9. RabbitMQ 消息队列幂等性,优先级队列,惰性队列的详细说明 文章目录 9. RabbitMQ 消息队列幂等性,优先级队列,惰性队列的详细说明1. RabbitMQ 消息队列的 “ 幂等性 ” 的问题1.1 RabbitMQ 消息队列的“幂等性”的概念 2. Rabbi…...
k8s创建一个pod,查看状态和详细信息,进入pod,以及删除这个pod
在 Kubernetes(K8s)中,可以使用 kubectl 命令行工具来完成创建 Pod、查看状态和详细信息、进入 Pod 以及删除 Pod 的操作。以下是具体步骤: 创建一个 Pod: 假设你有一个简单的 nginx Pod 的 YAML 配置文件 nginx…...
从盲目清运到精准调度:一个AI芯片引发的智慧环卫升级
在深圳某科技园区的清晨,环卫工人老张发现一个奇怪现象:往常需要逐个检查的50个智能垃圾桶,今天系统自动标注了7个待清运点位。这背后是搭载全志T113-i处理器的智能垃圾桶系统在发挥作用,通过AI视觉识别将垃圾满溢检测准确率提升至…...
MQTT协议:IoT通信的轻量级选手
文章总结(帮你们节约时间) MQTT协议是一种轻量级的发布/订阅通信协议。MQTT通信包括连接建立、订阅、发布和断开等过程。MQTT基于TCP/IP,其通信过程涉及多种控制包和数据包。ESP32S3可以通过MQTT协议接收消息来控制IO9引脚上的LED。 想象一…...
Docker 入门指南:基础知识解析
1. 引言 1.1 为什么学习 Docker 1.1.1 Docker 的优势 环境一致:在不同环境中(开发、测试、生产)保持一致的运行环境。快速部署:容器启动速度快,适合微服务架构。资源隔离:容器之间相互隔离,避…...
【安当产品应用案例100集】043-安当物联网数据安全传输方案
一、需求背景 物联网(IoT)技术在当前世界各行业中的应用越来越广泛,数据安全和安全数据传输、鉴权成为了物联网解决方案不可或缺的一部分。如何通过有效的安全措施来保护物联网设备的数据传输和鉴权,确保数据在设备和服务器之间或…...
C#/.NET/.NET Core技术前沿周刊 | 第 33 期(2025年4.1-4.6)
前言 C#/.NET/.NET Core技术前沿周刊,你的每周技术指南针!记录、追踪C#/.NET/.NET Core领域、生态的每周最新、最实用、最有价值的技术文章、社区动态、优质项目和学习资源等。让你时刻站在技术前沿,助力技术成长与视野拓宽。 欢迎投稿、推荐…...
Django视图详解
前言 欢迎来到我的博客 个人主页:北岭敲键盘的荒漠猫-CSDN博客 一、Django视图是什么? 视图(View) 是Django处理HTTP请求的核心组件。它接收一个HttpRequest对象,处理业务逻辑,并返回一个HttpResponse对象(…...
【区块链+ 人才服务】北京师范大学区块链底层链平台 | FISCO BCOS 应用案例
北京师范大学是教育部直属重点大学,2018 年 6 月,北京师范大学成立知识区块链研究中心,致力于区块链基础技术及其在教育领域的应用研究。 2020 年6 月18 日, 北京市人民政府办公厅发布《北京市区块链创新发展行 动计划(2020—202…...
java设计模式-模板方法模式
模板方法模式 编写制作豆浆的程序,说明如下 1)制作豆浆的流程选材添加配料浸泡放到豆浆机打碎 2)通过添加不同的配料,可以制作出不同口味的豆浆 3)选材、浸泡和放到豆浆机打碎这几个步骤对于制作每种口味的豆浆都是一样的 4)请使用模板方法模式完成 说明…...
同步通信、异步通信、并行传输和串行传输
同步通信、异步通信、并行传输和串行传输是通信与数据传输领域的关键概念,它们既相互关联又有本质区别。以下是详细解释和对比: 1. 核心概念分类 通信方式:描述数据传输的时序和协调规则。 同步通信(Synchronous Communi…...
JVM生产环境调优实战
案例三:JVM频繁Full GC优化 1. 项目背景(Situation) 在云中万维跨境支付的反洗钱系统中,我们负责对海量交易数据进行实时规则校验,以确保符合监管要求。系统日均处理交易量超过500万笔,峰值QPS达到3000&a…...
Python: sqlite3.OperationalError: no such table: ***解析
出现该错误说明数据库中没有成功创建 reviews 表。以下是完整的解决方案: 步骤 1:创建数据库表 在插入数据前,必须先执行建表语句。请通过以下任一方式创建表: 方式一:使用 SQLite 命令行 bash 复制 # 进入 SQLit…...
JVM考古现场(十七):鸿蒙初辟——从太极二进到混沌原初的编译天道
"此刻正是奇点编译的第3.1415926秒!伏羲的算筹正在撕裂冯诺依曼架构的次元壁!诸君请看——这JVM堆内存中正在孕育盘古的元神!" 目录(终极扩展) 第一章:太极二进——内存模型的阴阳交缠 第二章&a…...
Python 字典和集合(字典推导)
本章内容的大纲如下: 常见的字典方法 如何处理查找不到的键 标准库中 dict 类型的变种set 和 frozenset 类型 散列表的工作原理 散列表带来的潜在影响(什么样的数据类型可作为键、不可预知的 顺序,等等) 字典推导 自 Python 2.7 …...
【AI】prompt engineering
prompt engineering ## prompt engineering ## prompt engineering ## prompt engineering 一、定义 Prompt 工程(Prompt Engineering)是指在使用语言模型(如 ChatGPT、文心一言等)等人工智能工具时,设计和优化输入提…...
小刚说C语言刷题——第18讲 循环之while和do-while语句
昨天我们讲了循环语句中的for语句,它主要用于循环次数已知的情况,但是对应循环次数未知的情况,我们又怎么办?这就要用到while和do-while语句了。 1.while语句 (1)语法格式 while(条件表达式) { 循环体; } (2)执行过程 当执…...
[Mysql]buffersize修改
1、找到my.cnf文件位置 ps -ef|grep mysqld 2、编辑my.cnf cd /etc/my.cnf.d vim my.cnf 一般修改为内存的50%~70% 3、重启服务 systemctl restart mysqld...
自定义数据结构的QVariant序列化 ASSERT failure in QVariant::save: “invalid type to save“
自定义数据结构放入QVariant,在序列化时抛出异常 ASSERT failure in QVariant::save: “invalid type to save” 自定义数据结构如struct MyData,除了要在结构体后面加 struct MyData { ... } Q_DECLARE_METATYPE(MyData)如果需要用到流的输入输出&…...
带约束的智能优化算法
带约束的智能优化算法 约束条件和优化问题(可改)粒子群算法麻雀搜索算法鲸鱼优化算法灰狼优化算法免疫优化算法人工蜂群算法沙猫群算法萤火虫算法资源 约束条件和优化问题(可改) 粒子群算法 麻雀搜索算法 鲸鱼优化算法 灰狼优化算法 免疫优化算法 人工蜂群算法 沙猫群算法 萤火…...
【硬核实战】从零打造智能五子棋AI:JavaScript实现与算法深度解析
🌟【硬核实战】从零打造智能五子棋AI:JavaScript实现与算法深度解析🌟 📜 前言:当传统棋艺遇上人工智能 五子棋作为中国传统棋类游戏,规则简单却变化无穷。本文将带你用纯前端技术实现一个具备AI对战功能…...
使用 kind 创建 K8s 集群并部署 StarRocks 的完整指南
使用 kind 创建 K8s 集群并部署 StarRocks 的完整指南 本文档详细介绍如何使用 kind 创建 Kubernetes 集群,并在其上使用 Helm 部署 StarRocks 集群(非高可用模式)。同时也包括如何访问 StarRocks 集群并导入数据。 目录 前提条件参考文档…...
华为OD全流程解析+备考攻略+经验分享
华为OD全流程解析,备考攻略 快捷目录 华为OD全流程解析,备考攻略一、什么是华为OD?二、什么是华为OD机试?三、华为OD面试流程四、华为OD薪资待遇及职级体系五、ABCDE卷类型及特点六、题型与考点七、机试备考策略八、薪资与转正九、…...
数据库中的数组: MySQL与StarRocks的数组操作解析
在现代数据处理中, 数组 (Array) 作为一种高效存储和操作结构化数据的方式, 被广泛应用于日志分析, 用户行为统计, 标签系统等场景. 然而, 不同数据库对数组的支持差异显著. 本文将以MySQL和StarRocks为例, 深入解析它们的数组操作能力, 并对比其适用场景. 文章目录 一 为什么需…...
Qt 交叉编译详细配置指南
一、Qt 交叉编译详细配置 1. 准备工作 1.1 安装交叉编译工具链 # 例如安装ARM工具链(Ubuntu/Debian) sudo apt-get install gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf# 或者64位ARM sudo apt-get install gcc-aarch64-linux-gnu g++-aarch64-linux-gnu 1.2 准备目标…...
【详细图文】在VScode中配置python开发环境
目录 一、下载安装VSCode 1、官网下载VSCode 2、安装VSCode 3、汉化vscode (1)已自动下载汉化版插件 (2)未自动下载汉化版插件 二、 下载安装Python 1、官网下载Python 2、安装Python (1)双击打开…...
strings.Fields 使用详解
目录 1. 官方包 2. 支持版本 3. 官方说明 4. 作用 5. 实现原理 6. 推荐使用场景和不推荐使用场景 推荐场景 不推荐场景 7. 使用场景示例 示例1:官方示例 示例2:解析服务器日志 示例3:清理用户输入 8. 性能比较 性能特点 对比表…...
PCI认证 密钥注入 ECC算法工具 NID_secp521r1 国密算法 openssl 全套证书生成,从证书提取公私钥数组 x,y等
步骤 1.全套证书已经生成。OK 2.找国芯要ECC加密解密签名验签代码。给的逻辑说明没有示例代码很难的上。 3.集成到工具 与SP联调。 1.用openssl全套证书生成及验证 注意:这里CA 签发 KLD 证书用的是SHA256。因为芯片只支持SHA256算法,不支持SHA512。改成统一。…...
微软 SC-900 认证-考核Azure 和 Microsoft 365中的安全、合规和身份管理(SCI)概念
微软 SC-900 认证介绍 SC-900 认证考试是微软推出的一项基础级别认证,全称为 Microsoft Certified: Security, Compliance, and Identity Fundamentals。该认证旨在验证考生对微软云服务(如 Azure 和 Microsoft 365)中的安全、合规和身份管理…...
Uniapp 集成极光推送(JPush)完整指南
文章目录 前言一、准备工作1. 注册极光开发者账号2. 创建应用3. Uniapp项目准备 二、集成极光推送插件方法一:使用UniPush(推荐)方法二:手动集成极光推送SDK 三、配置原生平台参数四、核心功能实现1. 获取RegistrationID2. 设置别…...
OpenCV图像平滑处理方法详解
文章目录 引言一、什么是图像平滑?二、常见的图像平滑方法1.先对图片加上噪声点2. 均值滤波(Averaging)3. 方框滤波(boxFilter)4. 中值滤波(Median Blur)5. 高斯滤波(Gaussian Blur&…...
Lua 中,`math.random` 的详细用法
在 Lua 中,math.random 是用于生成伪随机数的核心函数。以下是其详细用法、注意事项及常见问题的解决方案: Lua 中,math.random 的详细用法—目录 一、基础用法1. 生成随机浮点数(0 ≤ x < 1)2. 生成指定范围的随机…...
使用PX4,gazebo,mavros为旋翼添加下视的相机(仿真采集openrealm数据集-第一步)
目录 一.方法一(没成功) 1.运行PX4 2.运行mavros通讯 3.启动仿真世界和无人机 (1)单独测试相机 (2)make px4_sitl gazebo启动四旋翼iris无人机 二.方法二(成功) 1.通过 rosl…...
ATEngin开发记录_4_使用Premake5 自动化构建跨平台项目文件
该系列只做记录 不做教程 所以文章简洁直接 会列出碰到的问题和解决方案 只适合C萌新 文章目录 Permake5为什么使用 Premake? 项目实战总结一下:详细代码: Permake5 Premake5 是一个跨平台的构建配置工具,它允许开发者通过使用一个简单的脚…...
equals() 和 hashCode()
作为 Java 开发者,我们经常会用到 equals() 和 hashCode() 这两个方法。 它们是 Object 类中定义的基础方法,看似简单,但如果理解不透彻,很容易在实际开发中踩坑。 本文将深入探讨这两个方法的作用、区别、以及如何正确地重写它们…...
臭氧除菌柜市场报告:2031年全球臭氧除菌柜市场销售额预计将达到9.4亿元
一、市场概述 (一)定义与分类 臭氧除菌柜,作为新一代绿色消毒设备,主要利用臭氧(O₃)的强氧化性来实现无化学残留的消毒净化。根据产品类型,可分为单门型和双门型。单门型设计紧凑,…...
解决python manage.py shell ModuleNotFoundError: No module named xxx
报错如下: python manage.py shellTraceback (most recent call last):File "/Users/z/Documents/project/c/manage.py", line 10, in <module>execute_from_command_line(sys.argv)File "/Users/z/.virtualenvs/c/lib/python3.12/site-packa…...
通用接口函数注册模块设计与实现
文章目录 通用接口函数注册模块设计与实现1. 模块概述2. 核心功能2.1 数据结构函数注册项结构体注册函数宏 2.2 核心函数实现函数:sl_register_interface_functions 3. 使用示例3.1 基础使用示例 - 设备驱动接口定义接口结构体实现具体函数创建注册表注册接口 3.2 高…...
C,C++,C#
C、C 和 C# 是三种不同的编程语言,虽然它们名称相似,但在设计目标、语法特性、运行环境和应用场景上有显著区别。以下是它们的核心区别: 1. 设计目标和历史 语言诞生时间设计目标特点C1972(贝尔实验室)面向过程&#…...
scala-集合3
集合计算高级函数 过滤:遍历一个集合并从中获取满足指定条件的元素组成一个新的集合 (筛选出满足条件的元素组成新集合。) 转换或映射(map):将原始集合中的元素映射到某个函数。 扁平化:取消…...
Spring MVC 重定向(Redirect)详解
Spring MVC 重定向(Redirect)详解 1. 核心概念与作用 重定向(Redirect) 是 Spring MVC 中一种客户端重定向机制,通过 HTTP 302 状态码(默认)将用户浏览器重定向到指定 URL。 主要用途…...
Scala的集合(二)
1. 集合计算高集函数 任务要求 1)过滤:遍历一个集合并从中获取满足指定条件的元素组成一个新的集合 2)转化/映射(map):将集合中的每一个元素映射到某一个函数 3)扁平化 4)扁平化映射 注:flatMap 相当于先进行 map 操作&#…...
GZ036区块链卷三 EtherGame合约漏洞详解
题目 pragma solidity ^0.8.3; contract EtherGame {uint public targetAmount 7 ether;address public winner;function deposit() public payable {require(msg.value 1 ether, "You can only send 1 Ether");uint balance address(this).balance;require(bala…...
BGP路由协议之路由通告/传递
BGP 的路由宣告 BGP 自身并不会发现并计算产生路由,只会将 IGP 路由表中的路由引入到 BGP 路由表中,并通过 Update 报文传递给 BGP 对等体(邻居) Network 宣告,前提是路由表中存在该条路由 import-route 引…...
Python合并多个pdf
场景: 现在要解决批量合并PDF的问题。 有很多PDF文件需要合并成一个,比如报告、发票或者多个章节的文档。 对于Windows用户,Adobe Acrobat是专业的选择,但需要付费。但是我不想花钱,所以推荐免费软件,比…...
聊一聊接口测试时遇到上下游依赖时该如何测试
目录 一、手工测试时的处理方法 1.1沟通协调法 1.2模拟数据法 二、自动化测试时的处理方法 2.1 数据关联法(变量提取) 2.2 Mock数据法 2.3自动化框架中的依赖管理 三、实施示例(以订单接口测试为例) 3.1Mock依赖接口&…...
pdf转latex
Doc2X(https://doc2x.noedgeai.com/) Doc2X 是一个由 NoEdgeAI 提供的在线工具,主要用于将 PDF 文件(尤其是学术论文、报告等文档)转换为 LaTeX 格式。LaTeX 是一种高质量排版系统,广泛应用于学术界和出版…...
剖析 Docker Swarm 操作对原有容器端口影响
剖析 Docker Swarm 操作对容器端口影响 一、背景阐述 在使用 Docker Swarm 构建集群环境过程中,于 ts3 节点出现了原有的容器端口全部失效,手动重启后才恢复的情况。期间涉及 docker swarm init --advertise-addr172.16.10.110 以及 docker swarm join…...
QML面试笔记--UI设计篇02布局控件
1. QML 中常用的布局控件 1.1. Row1.2. Column1.3. Grid1.4. RowLayout1.5. ColumnLayout1.6. GridLayout1.7. 总结 1. QML 中常用的布局控件 1.1. Row 背景知识:Row 布局用于将子元素水平排列,适合简单的线性布局,如工具栏按钮或表单输入…...
Java全栈项目--校园快递管理与配送系统(4)
源代码续 /*** 通知工具类*/// 通知类型常量 export const NotificationType {SYSTEM: 1,EXPRESS: 2,ACTIVITY: 3 }// 通知类型名称映射 export const NotificationTypeNames {[NotificationType.SYSTEM]: 系统通知,[NotificationType.EXPRESS]: 快递通知,[NotificationType…...