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

RabbitMQ之快速入门、上手

前言

学习一样新技术、新框架,最重要的是学习其思想、原理。即原理性思维。

如果是因为工作原因,需要快速上手RabbitMQ,本篇或许适合你。

核心概念

  • Connection:publisher/consumer 和 broker 之间的 TCP 连接
  • Channel: 消息通道,在客户端的每个连接里,可建立多个channel,每个channel代表一个会话任务
  • Exchange: 消息交换机,它指定消息按什么规则,路由到哪个队列
  • Queue: 消息队列载体,每个消息都会被投入到一个或多个队列
  • VHost: 虚拟主机,一个broker里可以开设多个vhost,用作不同用户的权限分离

image.png

安装

  • 修改host,添加下面数据

192.168.204.179 rabbit

  • 拉取镜像

docker pull rabbitmq:3.8.2-management

  • 启动容器
docker run -d --restart=always \--hostname rabbit \--name=rabbitmq \-p 5671:5617 -p 5672:5672 -p4369:4369 -p 15671:15671 -p 15672:15672 -p 25672:25672 \rabbitmq:3.8.2-management 

5671:开启管理插件时,管理界面接口
5671、5672:AMQP
4369:守护进程
25672:

用户、Virtual Host管理

用户角色

访问管理界面:192.168.204.179:15672
默认账号密码:guest

角色列表:

  • 超级管理员(administrator)可登陆管理控制台,可查看所有的信息,并且可以对用户,策略(policy)进行操作。
  • 监控者(monitoring)可登陆管理控制台,同时可以查看rabbitmq节点的相关信息(进程数,内存使用情况,磁盘使用情况等)
  • 策略制定者(policymaker)可登陆管理控制台, 同时可以对policy进行管理。但无法查看节点的相关信息(上图红框标识的部分)。
  • 普通管理者(management)仅可登陆管理控制台,无法看到节点信息,也无法对策略进行管理。
  • 其他无法登陆管理控制台,通常就是普通的生产者和消费者。

image.png

Virtual Hosts配置

每个虚拟主机就相当于一个独立的MQ服务器,虚拟主机之间相互隔离。

  • 创建虚拟主机,主机名称一般以/开头:

image.png

  • 权限设置:

image.png

添加队列

image.png

添加交换机

  • 添加交换机

image.png

  • 绑定Queue

image.png

整合SpringBoot

		<!--amqp协议的起步依赖坐标--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId></dependency><!--rabbit测试依赖坐标--><dependency><groupId>org.springframework.amqp</groupId><artifactId>spring-rabbit-test</artifactId><scope>test</scope></dependency><!--SpringBoot测试依赖坐标--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency>

# RabbitMQ 服务host地址
spring.rabbitmq.host=rabbit
# 端口
spring.rabbitmq.port=5672
# 虚拟主机地址
spring.rabbitmq.virtual-host=/mytest
# rabbit服务的用户名
spring.rabbitmq.username=test
# rabbit服务的密码
spring.rabbitmq.password=123456

五种工作模式

1.简单模式

image.png

  • 先添加一个Queue

image.png

  • 生产者
@RunWith(SpringRunner.class)
@SpringBootTest(classes = ProducerApplication.class)
public class MQTest {@Autowiredprivate RabbitTemplate rabbitTemplate;@Testpublic void contextLoads() {/*** 参数1:消息队列名称* 参数2:消息内容*/rabbitTemplate.convertAndSend("/myqueue", "hello 小兔子!");}}
  • 消费者
@Component
@RabbitListener(queues = "/myqueue")
public class SimpleListener {@RabbitHandlerpublic void simpleHandler(String msg){System.out.println("=====接收消息====>"+msg);}
}

2.工作队列模式

image.png
相比于简单模式,这个模式下会存在多个消费者。

  • 在普通模式基础上,增加订阅者即可:
@Component
@RabbitListener(queues = "/myqueue")
public class SimpleListener2 {@RabbitHandlerpublic void simpleHandler(String msg){System.out.println("=====222接收消息====>"+msg);}
}
  • 测试:
@RunWith(SpringRunner.class)
@SpringBootTest(classes = ProducerApplication.class)
public class MQTest {@Autowiredprivate RabbitTemplate rabbitTemplate;@Testpublic void contextLoads() {/*** 参数1:消息队列名称* 参数2:消息内容*/for (int i = 0; i < 10000; i++) {rabbitTemplate.convertAndSend("/myqueue", "hello 小兔子!" + i);}}}

交换机类型

image.png

消息将发给交换机,交换机的类型决定了它会怎么处理这个消息:

  • Direct(直连交换机):使用消息的 Routing Key 与队列的 Binding Key 进行精确匹配,只有消息的 Routing Key 与队列的 Binding Key 完全相同时,消息才会被路由到该队列。非广播
  • Fanout(扇形交换机):忽略消息的 Routing Key,直接将消息发送到所有与交换机绑定的队列。广播消息
  • Topic(主题交换机):使用通配符匹配的方式将消息路由到多个队列。通配符由字符 “#” 和 “” 组成,其中 “#” 表示匹配零个或多个单词,“” 表示匹配一个单词。支持灵活的消息路由。
  • Headers(头交换机):使用消息的 Headers 属性来匹配队列的 Binding Headers,从而确定消息的路由。较少使用,一般情况下使用 Direct、Fanout 或 Topic 类型的交换机就能满足大部分场景。

符号 “#” 匹配一个或多个词,符号""匹配不多不少一个词。因此“audit.#” 能够匹配到“audit.irs.corporate”,但是“audit.” 只会匹配到 “audit.irs”。

总结就是交换机负责消息转发,不进行数据存储,如果没有找到绑定的队列或匹配的队列,消息将会丢失。

3.广播模式

将同一个消息广播到订阅的多个消费者手中。

创建队列和交换机

添加队列
添加交换机
绑定队列到交换机

生产者
@RunWith(SpringRunner.class)
@SpringBootTest(classes = ProducerApplication.class)
public class MQSPTest {@Autowiredprivate RabbitTemplate rabbitTemplate;@Testpublic void contextLoads() {/*** 参数1:消息队列名称* 参数2:消息内容*/for (int i = 0; i < 10000; i++) {rabbitTemplate.convertAndSend("/fanout_exchange", null, "hello 小兔子!" + i);}}}
消费者
@Component
@RabbitListener(queues = "/fanout_queue1")
public class SimpleListener_Fanout1 {@RabbitHandlerpublic void simpleHandler(String msg){System.out.println("=====222接收消息====>"+msg);}
}@Component
@RabbitListener(queues = "/fanout_queue2")
public class SimpleListener_Fanout2 {@RabbitHandlerpublic void simpleHandler(String msg){System.out.println("=====3333接收消息====>"+msg);}
}

4.路由模式

在将队列绑定到交换机的时候,需要指定路由key;发送消息的时候也要指明路由key。
image.png

配置交换机

image.png

生产者

/*** 路由**/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = ProducerApplication.class)
public class MQRoutingTest {@Autowiredprivate RabbitTemplate rabbitTemplate;@Testpublic void contextLoads() {/*** 参数1:消息队列名称* 参数2:消息内容*/for (int i = 0; i < 10000; i++) {if (i % 2 == 0) {rabbitTemplate.convertAndSend("/routing_exchange", "info", "hello 小兔子!" + i);} else {rabbitTemplate.convertAndSend("/routing_exchange", "err", "hello 小黑子!" + i);}}}}
消费者
@Component
@RabbitListener(queues = "/routing_err1")
public class Routing_Err1 {@RabbitHandlerpublic void simpleHandler(String msg){System.out.println("=====routing_err1接收消息====>"+msg);}
}@Component
@RabbitListener(queues = "/routing_err2")
public class Routing_Err2 {@RabbitHandlerpublic void simpleHandler(String msg){System.out.println("=====routing_err2接收消息====>"+msg);}
}@Component
@RabbitListener(queues = "/routing_info1")
public class Routing_info1 {@RabbitHandlerpublic void simpleHandler(String msg){System.out.println("=====routing_info1接收消息====>"+msg);}
}

5.主题模式(通配符)

#:匹配零个或多个。
*:匹配一个。
image.png

配置

image.png

生产者

/*** topc**/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = ProducerApplication.class)
public class MQTopicTest {@Autowiredprivate RabbitTemplate rabbitTemplate;@Testpublic void contextLoads() {/*** 参数1:消息队列名称* 参数2:消息内容*/for (int i = 0; i < 10000; i++) {if (i % 2 == 0) {rabbitTemplate.convertAndSend("/topic_exchange", "test.info", "hello 小兔子!" + i);} else {rabbitTemplate.convertAndSend("/topic_exchange", "test.err", "hello 小黑子!" + i);}rabbitTemplate.convertAndSend("/topic_exchange", "my.test.warn", "hello 小白子!" + i);}}}
消费者
@Component
@RabbitListener(queues = "/topic_info")
public class Topic1 {@RabbitHandlerpublic void simpleHandler(String msg){System.out.println("=====topic_info接收消息====>"+msg);}
}@Component
@RabbitListener(queues = "/topic_err")
public class Topic2 {@RabbitHandlerpublic void simpleHandler(String msg){System.out.println("=====topic_err接收消息====>"+msg);}
}@Component
@RabbitListener(queues = "/topic_warn")
public class Topic3 {@RabbitHandlerpublic void simpleHandler(String msg){System.out.println("=====topic_warn接收消息====>"+msg);}
}

工作模式总结

  • 简单模式:一个生产者和一个消费者,无需交换机。
  • 工作队列模式:一个生产者,多个消费者(竞争消息),无需交换机。
  • 发布订阅模式:fanout类型的交换机。消费广播到每个绑定的queue中。
  • 路由模式:direct类型的交换机。消息发送到路由key精确匹配的队列中。
  • 通配符模式:topic类型的交换机。消息发送到通配符匹配的路由key的队列中。

高级特性

生产者确认

rabbitmq提供了两种方式来保证投递的可靠性:

  • confirm 确认模式:消息发到交换机,不管是否成功,都回调confirmCallback。
  • return 退回模式:投递失败会回调returnCallback。
配置
spring:rabbitmq:password: 123456username: testvirtualHost: /mytestport: 5672host: rabbitpublisherReturns: truepublisherConfirmType: SIMPLE
案例
@Slf4j
public class RabbitConfirmCallback implements RabbitTemplate.ConfirmCallback{@Overridepublic void confirm(CorrelationData correlationData, boolean ack, String cause) {if (ack) {log.info("消息发送到exchange成功");} else {log.info("消息发送到exchange失败");}}
}@Slf4j
public class RabbitReturnCallback implements RabbitTemplate.ReturnsCallback {@Overridepublic void returnedMessage(ReturnedMessage returnedMessage) {log.info("消息发送失败:{}", returnedMessage.getMessage());}
}@Configuration
public class RabbitCallBackConfig {@Resourceprivate RabbitTemplate rabbitTemplate;@PostConstructpublic void initRabbitTemplate(){rabbitTemplate.setConfirmCallback(new RabbitConfirmCallback());rabbitTemplate.setReturnsCallback(new RabbitReturnCallback());}}@RestController
public class TestController {@Resourceprivate RabbitTemplate rabbitTemplate;@GetMapping("confirmCallBack")public String confirmCallBack() {for (int i = 0; i < 10000; i++) {rabbitTemplate.convertAndSend("/routing_exchange", "err", "hello 小黑子!" + i);}return "ok";}@GetMapping("returnCallBack")public String returnCallBack() {for (int i = 0; i < 10000; i++) {// 不存在的routingkeyrabbitTemplate.convertAndSend("/routing_exchange", "err2", "hello 小黑子!" + i);}return "ok";}}

消费者确认

消费者消息确认有三种类型:

  • 无确认:none。收到生产者的消息之后,直接ACK。
  • 手动确认:manual。消费者需要显式的告诉RabbitMQ消息已经确认。手动确认更安全。
  • 自动确认:auto。客户端收到消息之后,mq自动ACK。

为什么手动确认更安全?
消费者处理消息失败时,可以重新处理消息。其它优势:1.消费者可以根据处理能力控制消费速率;2.批量确认多个信息。


import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.listener.api.ChannelAwareMessageListener;
import org.springframework.stereotype.Component;import java.util.concurrent.atomic.AtomicInteger;/*** 自定义监听器,监听到消息之后,立即执行onMessage方法*/
@Component
public class CustomAckConsumerListener implements ChannelAwareMessageListener {private static final AtomicInteger errCount = new AtomicInteger();/*** 监听到消息之后执行的方法** @param message 消息内容* @param channel 消息所在频道*/@Overridepublic void onMessage(Message message, Channel channel) throws Exception {//获取消息内容byte[] messageBody = message.getBody();String msg = new String(messageBody, "UTF-8");System.out.println("接收到消息,执行具体业务逻辑{} 消息内容:" + msg);//获取投递标签MessageProperties messageProperties =message.getMessageProperties();long deliveryTag = messageProperties.getDeliveryTag();// 模拟业务错误if(errCount.getAndIncrement() % 2 == 0) {System.out.println("业务报错,重回队列");channel.basicNack(deliveryTag, false, true);return;}// 签收消息,前提条件,必须在监听器的配置中,开启手动签收模式// 参数1:消息投递标签// 数2:是否批量签收:true一次性签收所有,false,只签收当前消息channel.basicAck(deliveryTag, false);System.out.println("手动签收完成:{}");}
}

import cn.lsj.consumer.listener.CustomAckConsumerListener;
import org.springframework.amqp.core.AcknowledgeMode;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class ListenerConfiguration {/*** 注入消息监听器适配器** @param customAckConsumerListener 自定义监听器对象*/@Beanpublic MessageListenerAdapter messageListenerAdapter(CustomAckConsumerListener customAckConsumerListener) {//创建自定义监听器适配器对象return new MessageListenerAdapter(customAckConsumerListener);}/*** 注入消息监听器容器** @param connectionFactory      连接工厂* @param messageListenerAdapter 自定义的消息监听器适配器*/@Beanpublic SimpleMessageListenerContainer simpleMessageListenerContainer(ConnectionFactory connectionFactory, MessageListenerAdapter messageListenerAdapter) {//简单的消息监听器容器对象SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();//绑定消息队列container.setQueueNames("/routing_err3");//设置连接工厂对象container.setConnectionFactory(connectionFactory);//设置消息监听器适配器container.setMessageListener(messageListenerAdapter);//设置手动确认消息:NONE(不确认消息),MANUAL(手动确认消息),AUTO(自 动确认消息)container.setAcknowledgeMode(AcknowledgeMode.MANUAL);return container;}}

消费端限流

应用场景:

  • 宕机恢复之后处理大量的积压消息导致业务系统再次崩溃。
  • 短时间大量请求来到,业务系统不支持同时处理那么多的消息。

要求:必须为手动确认消息。

package cn.lsj.consumer.config;import cn.lsj.consumer.listener.CustomAckConsumerListener;
import org.springframework.amqp.core.AcknowledgeMode;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class ListenerConfiguration {/*** 注入消息监听器适配器** @param customAckConsumerListener 自定义监听器对象*/@Beanpublic MessageListenerAdapter messageListenerAdapter(CustomAckConsumerListener customAckConsumerListener) {//创建自定义监听器适配器对象return new MessageListenerAdapter(customAckConsumerListener);}/*** 注入消息监听器容器** @param connectionFactory      连接工厂* @param messageListenerAdapter 自定义的消息监听器适配器*/@Beanpublic SimpleMessageListenerContainer simpleMessageListenerContainer(ConnectionFactory connectionFactory, MessageListenerAdapter messageListenerAdapter) {//简单的消息监听器容器对象SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();//绑定消息队列container.setQueueNames("/routing_err3");//设置连接工厂对象container.setConnectionFactory(connectionFactory);//设置消息监听器适配器container.setMessageListener(messageListenerAdapter);//设置手动确认消息:NONE(不确认消息),MANUAL(手动确认消息),AUTO(自 动确认消息)container.setAcknowledgeMode(AcknowledgeMode.MANUAL);//设置消费端限流,每次拉取消息多少条,默认是250条container.setPrefetchCount(1);return container;}}

TTL(消息存活时间)

消息过期时间到未被消费则被自动清楚。

可以针对消息设置,也可以针对队列设置。

消息过期时间
rabbitTemplate.convertAndSend("/routing_exchange", "err", "hello 小黑子!" + count.getAndIncrement(), m -> {// 10秒m.getMessageProperties().setExpiration(String.valueOf(10000L));return m;
});
队列过期时间

参数message-TTL ,单位毫秒,在创建队列的时候添加。
image.png

注意点
  • 消息过期的优先级高于队列;
  • 即使消息已经过期,也要等到前面的消费被消费或删除才进一步处理,所以要注意消息堆积的情况。

死信队列

是什么

当消息过期未消费;当消费者拒接消息且不放回源队列;当队列队列达到最大限度时。

以上三个场景,导致了Dead message(死消息)的产生。
image.png

如何设置死信队列

image.png

延迟队列

是什么

消息到达队列之后,不会马上被消费,而是等待一段时间之后才会被消费。

应用场景
  • 定时任务;
  • 订单超时;
  • 定时通知;
  • 消息重试\错误重试:消息放入延迟队列,过一段时间重试;
如何实现?

死信队列配合过期队列实现延迟队列

如下图,我们不设置过期队列的消费者,让消息过期之后进入死信队列,达到延迟效果。
image.png

相关文章:

RabbitMQ之快速入门、上手

前言 学习一样新技术、新框架&#xff0c;最重要的是学习其思想、原理。即原理性思维。 如果是因为工作原因&#xff0c;需要快速上手RabbitMQ&#xff0c;本篇或许适合你。 核心概念 Connection&#xff1a;publisher&#xff0f;consumer 和 broker 之间的 TCP 连接Channel…...

GBASE南大通用-GBase 8s数据库日志模式及切换

一、 GBase 8s数据库共有以下 4 种日志模式&#xff1a;无日志模式、缓冲日志模式、无缓冲日志模式、ANSI 模式。详细介绍如下&#xff1a; 1、无日志模式&#xff08;Non logging&#xff09;&#xff1a; 采用无日志模式时&#xff0c;所有 DML 操作都不会被记录到日志中&…...

侵入式和非侵入式微服务框架的比较

微服务框架可以分为侵入式和非侵入式两种。侵入式框架需要对现有代码进行改造&#xff0c;而非侵入式框架则无需改造现有代码。 侵入式框架 侵入式框架将微服务治理功能嵌入到应用程序中&#xff0c;需要修改应用程序的代码。这种框架的优点是可以提供更强大的功能&#xff0…...

Go语言程序设计-第5章--函数

Go语言程序设计-第5章–函数 5.1 函数声明 每个函数声明都包含一个名字、一个形参列表、一个可选的返回列表以及函数体: func name(parameter-list) (result-list) {body }func add(x int, y int) int { return x y} func sub(x, y int) (z int) {z x - y; return} func f…...

数据被锁?被.mkp 勒索病毒攻击后的拯救行动

导言&#xff1a; 网络安全面临着越来越多的挑战&#xff0c;而.mallox勒索病毒则成为数字威胁中的一股强大势力。它的威胁不仅体现在其高度复杂的加密算法上&#xff0c;还表现在对受感染系统的深度渗透和数据的极大破坏上。以下是.mallox勒索病毒的主要威胁&#xff1a;如不…...

Fine-Tuning Language Models from Human Preferences

Abstract 奖励学习(reward learning)可以将强化学习(RL)应用到由人类判断定义奖励的任务中,通过询问人类问题来构建奖励模型。奖励学习的大部分工作使用了模拟环境,但是关于价值的复杂信息经常是以自然语言的形式表达的。我们相信语言奖励学习是使强化学习在现实世界任务…...

提升数据库性能的关键指南-Oracle AWR报告

文章目录 一、了解AWR报告&#xff1a;数据库性能的仪表盘二、生成AWR报告三、解读AWR报告的关键部分1.报告开头的系统基础信息2.ADDM发现3.负载概览(Load Profile)4.参数文件5.顶级前台等待事件6.SQL 统计信息-顶级SQL7.SGA Advisory AND PAG Advisory 一、了解AWR报告&#x…...

云计算IaaS、PaaS和SaaS之

提供的服务来比较如下两图 示例图 示例图...

解锁大数据世界的钥匙——Hadoop HDFS安装与使用指南

目录 1、前言 2、Hadoop HDFS简介 3、Hadoop HDFS安装与配置 4、Hadoop HDFS使用 5、结语 1、前言 大数据存储与处理是当今数据科学领域中最重要的任务之一。随着互联网的迅速发展和数据量的爆炸性增长&#xff0c;传统的数据存储和处理方式已经无法满足日益增长的需求。…...

写在2023岁末:敏锐地审视量子计算的当下

本周&#xff0c;《IEEE Spectrum》刊登了一篇出色的文章&#xff0c;对量子计算&#xff08;QC&#xff09;的近期前景进行了深入探讨。 文章的目的并不是要给量子计算的前景泼冷水&#xff0c;而是要说明量子计算的前景还很遥远&#xff0c;并提醒读者量子计算的用例可能很窄…...

C/C++学习笔记十三 C++中的重载运算符

1、什么是运算符重载&#xff1f; 运算符重载是 C 中的一项功能&#xff0c;使运算符&#xff08;例如 、- 等&#xff09;能够处理用户定义的数据类型。这种机制称为编译时多态性&#xff0c;并提供了为不同数据类型定制运算符行为的优点。 例如&#xff0c;我们可以重载“”运…...

Java 实现自动获取法定节假日

一、背景 在实现业务需求的过程中&#xff0c;遇到了需要计算 x 个工作日后的日期需求。由于工作日是每年国务院发布的&#xff0c;调休和休假都没有规律&#xff0c;所以无法使用算法进行计算。 一般的实现方案是自己维护一个工作日和调休的表&#xff0c;或者去爬取国务院发…...

湘潭大学-2023年下学期-c语言-作业0x0a-综合1

A 求最小公倍数 #include<stdio.h>int gcd(int a,int b) {return b>0?gcd(b,a%b):a; }int main() {int a,b;while(~scanf("%d%d",&a,&b)){if(a0&&b0) break;printf("%d\n",a*b/gcd(a,b));}return 0; }记住最大公约数的函数&…...

网络协议-BIO实战和NIO编程

网络通信编程基本常识 在开发过程中&#xff0c;如果类的名字有 Server 或者 ServerSocket 的&#xff0c;表示这个类是给服务端容纳网络 服务用的&#xff0c;如果类的名字只包含 Socket 的&#xff0c;那么表示这是负责具体的网络读写的。 ServerSocket 并不负责具体的网络读…...

Word 将页面方向更改为横向或纵向

文章目录 更改整个文档的方向更改部分页面的方向方法1&#xff1a;方法2&#xff1a; 参考链接 更改整个文档的方向 选择“布局”>“方向”&#xff0c;选择“纵向”或“横向”。 更改部分页面的方向 需要达到下图结果&#xff1a; 方法1&#xff1a; 选:中你要在横向页面…...

关键字:abstract关键字

在 Java 中&#xff0c;abstract是一个关键字&#xff0c;用于修饰类和方法。当一个类被声明为抽象类时&#xff0c;它不能被实例化&#xff0c;只能被其他类继承。同时&#xff0c;抽象类可以包含抽象方法&#xff0c;抽象方法没有方法体&#xff0c;只包含方法的签名&#xf…...

从PDF中提取图片

由于工作需要&#xff0c;要从pdf文件中提取出图片保存到本地&#xff0c;项目中就引用到了Apache PDFBox库。 1 什么是Apache PDFBox? Apache PDFBox库&#xff0c;一个用于处理PDF文档的开源Java工具。它允许用户创建全新的PDF文件&#xff0c;操作现有的PDF文档&#xff0…...

推荐:一个不错的介绍Apache Doris的PPT

原来Apache Doris居然是百度开源出来的&#xff0c;不错。部分节选&#xff1a;完整下载地址网盘&#xff1a; 链接: https://pan.baidu.com/s/18WR70R_f72GxCjh0lykStQ 提取码: umd3 复制这段内容后打开百度网盘手机App&#xff0c;操作更方便哦 --来自百度网盘超级会员v7的分…...

【Python_PySide2学习笔记(二十二)】进度对话框QProgressDialog类的基本用法

进度对话框QProgressDialog类的基本用法 进度对话框QProgressDialog类的基本用法前言一、QProgressDialog 的常用方法1、创建进度对话框2、进度对话框设置窗口标题3、进度对话框隐藏"最大化"、"最小化"、"关闭"4、进度对话框设置是否自动关闭5、…...

使用rust读取usb设备ACR122U的nfc卡片id

rust及其高效和安全著称&#xff0c;而且支持跨平台&#xff0c;所以就想使用这个rust开发一个桌面端程序&#xff0c;来读取nfc设备的nfc卡片的id信息&#xff0c;下面就做一个最简单的入门教程吧&#xff0c;也是我写的第三个rust应用。 当你电脑上安装好了rust环境之后&…...

servlet总结

目录 1.生命周期 2.线程总结 3.配置 4.请求和响应 5.会话管理 6.过滤和监听器 7.处理表单数据 8.与JSP集成 9.异常处理 10.安全性和认证 Servlet是一种基于Java的Web组件&#xff0c;用于处理客户端请求并生成动态Web内容。以下是关于Servlet的一些总结 1.生命周期 …...

Nacos2.1.2改造适配达梦数据库7.0

出于业务需求&#xff0c;现将Nacos改造适配达梦数据库7.0&#xff0c;记录本次改造过程。 文章目录 一、前期准备二、适配流程1、项目初始化2、引入驱动3、源码修改 三、启动测试四、打包测试 一、前期准备 Nacos源码&#xff0c;版本&#xff1a;2.1.2&#xff1a;源码下载…...

TPRI-DMP平台介绍

TPRI-DMP平台介绍 1 TPRI-DMP平台概述 TPRI-DMP为华能集团西安热工院自主产权的工业云PaaS平台&#xff0c;已经过13年的发展和迭代&#xff0c;其具备大规模能源电力行业生产应用软件开发和运行能力。提供TPRI-DMP平台主数据管理、业务系统开发与运行、应用资源管理…...

oracle-存储结构

文件包括 控制文件.ctl、数据文件.dbf、日志文件.log这三类放在存储上。 参数文件&#xff1a;空间的划分&#xff0c;进程的选用&#xff08;.ora&#xff09; oracle启动的时候需要读一下&#xff0c;数据库启动后&#xff0c;参数文件并不关闭&#xff0c;但即使文件丢了&a…...

获取PG库 database与 user 创建时间以及cluster初始化时间

代码实现 echo "获取数据库创建时间" data_dir$(psql -U postgres -d postgres -X -qAt -c "show data_directory" ) db_dirs$(ls $data_dir/base |grep -v pgsql_tmp) for db_oid in $db_dirs dodb_exists$(psql -U postgres -d postgres -X -qAt -c &qu…...

【12.29】转行小白历险记-刷算法05

242.有效的字母异位词 数组、set、map&#xff0c;数组是比较高效查找的 函数功能 判断字符串 s 和 t 是否互为字母异位词。如果它们包含相同的字符且每个字符出现的次数也相同&#xff0c;那么它们互为字母异位词。 代码逻辑 长度检查&#xff1a; if (s.length ! t.lengt…...

docker部署kafka zookeeper模式集群

单机模式链接&#xff1a;https://blog.csdn.net/wsdhla/article/details/133032238 kraft集群模式链接&#xff1a;部署Kafka_kafka 部署-CSDN博客 zookeeper选举机制举例&#xff1a; 目前有5台服务器&#xff0c;每台服务器均没有数据&#xff0c;它们的编号分别是1,2,3,4,5…...

Apache Flink连载(二十一):Flink On Yarn运行原理-Yarn Application模式

🏡 个人主页:IT贫道_大数据OLAP体系技术栈,Apache Doris,Clickhouse 技术-CSDN博客 🚩 私聊博主:加入大数据技术讨论群聊,获取更多大数据资料。 🔔 博主个人B栈地址:豹哥教你大数据的个人空间-豹哥教你大数据个人主页-哔哩哔哩视频 目录 1. 任务提交命令...

《深入理解C++11:C++11新特性解析与应用》笔记五

第五章 提高类型安全 5.1 强类型枚举 5.1.1 枚举&#xff1a;分门别类与数值的名字 具名枚举类型一般声明类似&#xff1a;enum Gender { Male, Female }。 匿名枚举类型可以使用三种方式实现&#xff1a; 第一种方式时宏&#xff0c;比如 #define Male 0 #define Femal…...

Y9000P + ubuntu22.04 配置Anaconda+pycharm +pytorch

Anaconda3 的安装及使用方法安装 Anaconda3 Anaconda3 是 Anaconda 的具体版本 Anaconda3 中的 Python 解释器默认使用的是 Python3.x 版本&#xff0c;而不是 Python2.x 版本 Python2.x 版本中&#xff0c;字符串是以 ASCII 编码处理的&#xff0c;而在 Python3.x 版本中&am…...

高校网站一般采用什么网页布局/互联网怎么赚钱

电脑A ip &#xff1a;192.168.1.186 电脑B ip :192.168.1.1 用电脑A 去链接电脑B的本地数据库 1.互相 ping 看能否访问 如图 &#xff08;判断是否在一个局域网&#xff09; 2.给电脑A授权创建用户 电脑B操作 允许用户myuser从ip为 192.168.1.186 的主机连接到mysql服务器&a…...

DW怎么做网站下拉菜单/it培训机构排名

php爆绝对路径方法&#xff1f; 单引号引起数据库报错 访问错误参数或错误路径 探针类文件如phpinfo 扫描开发未删除的测试文件 google hacking phpmyadmin报路径&#xff1a;/phpmyadmin/libraries/lect_lang.lib.php 利用漏洞读取配置文件找路径 恶意使用网站功能&#xff0c…...

网站建设排行公司/seo优化平台

导读Dutree是Durep和Tree的组合。Durep用图表创建磁盘使用情况报告&#xff0c;这使我们能够确定哪些目录使用了最多的空间。尽管durep可以产生类似于du的文本输出&#xff0c;但其真正的功能是能够将报告存储在文件中。Tree是目录显示程序&#xff0c;它以树状结构在终端上递归…...

有赞网站开发/推广app最快的方法

Feign简介 Feign是Netflix开发的声明式&#xff0c;模板化的HTTP客户端&#xff0c;其灵感来自Retrofit,JAXRS-2.0以及WebSocket.Feign可帮助我们更加便捷&#xff0c;优雅的调用HTTP API。在SpringCloud中&#xff0c;使用Feign非常简单——创建一个接口&#xff0c;并在接口上…...

模拟人生4做游戏下载网站/cms快速建站

TD-ACC”(或 TD-ACS) 教学实验系统&#xff0c;其基本配臵就含有一个开放式的模拟实验平台和一组先进的虚拟仪器&#xff0c;可以高水平地支持自动控制原理的实验教学&#xff0c;若再选配“i386EX系统板”&#xff0c;就还可以开展“80X86 的计算机控制技术”的实验教学。i386…...

电商网站首页怎么制作/今日新闻最新头条

MYSQL数据库设计规范1、数据库命名规范采用26个英文字母(区分大小写)和0-9的自然数(经常不需要)加上下划线_组成;命名简洁明确(长度不能超过30个字符);例如&#xff1a;user, stat, log, 也可以wifi_user, wifi_stat, wifi_log给数据库加个前缀;除非是备份数据库可以加0-9的自然…...