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

RabbitMQ延迟队列

目录

一、概念

二、使用场景

三、RabbitMQ 中的 TTL

(一)队列设置 TTL

(二)消息设置 TTL

(三)两者的区别

四、整合SpringBoot实现延迟队列

(一)创建项目

(二)添加依赖

(三)修改配置文件

(四)添加Swagger配置类

五、队列TTL

(一)代码架构图

(二)配置文件类

(三)消息生产者

(四)消息消费者 

六、延迟队列优化

(一)代码架构图

(二)配置文件类

(三)消息生产者

七、Rabbitmq 插件实现延迟队列

(一)代码架构图

(二)配置文件类

(三)消息生产者

(四)消息消费者

八、总结


一、概念

        延时队列,队列内部是有序的,最重要的特性就体现在它的延时属性上,延时队列中的元素是希望在指定时间到了以后或之前取出和处理,简单来说,延时队列就是用来存放需要在指定时间被处理的元素的队列。

二、使用场景

  1. 订单在十分钟之内未支付则自动取消
  2. 新创建的店铺,如果在十天内都没有上传过商品,则自动发送消息提醒。
  3. 用户注册成功后,如果三天内没有登陆则进行短信提醒。
  4. 用户发起退款,如果三天内没有得到处理则通知相关运营人员。
  5. 预定会议后,需要在预定的时间点前十分钟通知各个与会人员参加会议
这些场景都有一个特点,需要在某个事件发生之后或者之前的指定时间点完成某一项任务,如:
发生订单生成事件,在十分钟之后检查该订单支付状态,然后将未支付的订单进行关闭;看起来似乎使用定时任务,一直轮询数据,每秒查一次,取出需要被处理的数据,然后处理不就完事了吗?如果数据量比较少,确实可以这样做,比如:对于“如果账单一周内未支付则进行自动结算”这样的需求,如果对于时间不是严格限制,而是宽松意义上的一周,那么每天晚上跑个定时任务检查一下所有未支付的账单,确实也是一个可行的方案。
但对于数据量比较大,并且时效性较强的场景,如:“订单十分钟内未支付则关闭“,短期内未支付的订单数据可能会有很多,活动期间甚至会达到百万甚至千万级别,对这么庞大的数据量仍旧使用轮询的方式显然是不可取的,很可能在一秒内无法完成所有订单的检查,同时会给数据库带来很大压力,无法满足业务要求而且性能低下。

 

 

三、RabbitMQ 中的 TTL

TTL RabbitMQ 中一个消息或者队列的属性,表明一条消息或者该队列中的所有消息的最大存活时间,单位是毫秒。换句话说,如果一条消息设置了 TTL 属性或者进入了设置 TTL 属性的队列,那么这条消息如果在 TTL 设置的时间内没有被消费,则会成为"死信"。如果同时配置了队列的 TTL 和消息的TTL,那么较小的那个值将会被使用,有两种方式设置 TTL

(一)队列设置 TTL

第一种是在创建队列的时候设置队列的“x-message-ttl”属性
Map<String, Object> arguments = new HashMap<>();
// 声明队列的TTL
arguments.put("x-message-ttl", 10000);
return QueueBuilder.durable(QUEUE_A).withArguments(arguments).build();

(二)消息设置 TTL

另一种方式便是针对每条消息设置 TTL

rabbitTemplate.convertAndSend("X", "XC", message, msg -> {msg.getMessageProperties().setExpiration(ttl);return msg;
});

(三)两者的区别

如果设置了队列的 TTL 属性,那么一旦消息过期,就会被队列丢弃(如果配置了死信队列被丢到死信队列中),而第二种方式,消息即使过期,也不一定会被马上丢弃,因为消息是否过期是在即将投递到消费者之前判定的如果当前队列有严重的消息积压情况,则已过期的消息也许还能存活较长时间;另外,还需要注意的一点是,如果不设置 TTL,表示消息永远不会过期,如果将 TTL 设置为 0,则表示除非此时可以直接投递该消息到消费者,否则该消息将会被丢弃。
前一小节我们介绍了死信队列,刚刚又介绍了 TTL,至此利用 RabbitMQ 实现延时队列的两大要素已经集齐,接下来只需要将它们进行融合,再加入一点点调味料,延时队列就可以新鲜出炉了。想想看,延时队列,不就是想要消息延迟多久被处理吗,TTL 则刚好能让消息在延迟多久之后成为死信,另一方面,成为死信的消息都会被投递到死信队列里,这样只需要消费者一直消费死信队列里的消息就完事了,因为里面的消息都是希望被立即处理的消息。

四、整合SpringBoot实现延迟队列

(一)创建项目

 

         

(二)添加依赖

        <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><!--RabbitMQ 依赖--><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.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.47</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><!--swagger--><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId><version>2.9.2</version></dependency><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger-ui</artifactId><version>2.9.2</version></dependency><!--RabbitMQ 测试依赖--><dependency><groupId>org.springframework.amqp</groupId><artifactId>spring-rabbit-test</artifactId><scope>test</scope></dependency>

(三)修改配置文件

spring.rabbitmq.host=192.168.23.100
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest

(四)添加Swagger配置类

@Configuration
@EnableSwagger2
public class SwaggerConfig {@Beanpublic Docket webApiConfig() {return new Docket(DocumentationType.SWAGGER_2).groupName("webapi").apiInfo(webApiInfo()).select().build();}public ApiInfo webApiInfo() {return new ApiInfoBuilder().title("rabbitmq 接口文档").description("本文档描述了 rabbitmq 微服务接口定义").version("1.0").contact(new Contact("enjoy6288", "http://atguigu.com","1551388580@qq.com")).build();}
}

五、队列TTL

(一)代码架构图

        创建两个队列 QA QB,两者队列 TTL 分别设置为 10S 40S,然后在创建一个交换机 X 和死信交换机 Y,它们的类型都是 direct,创建一个死信队列 QD,它们的绑定关系如下:

 

 (二)配置文件类

@Configuration
public class TtlQueueConfig {public static final String X_EXCHANGE = "X";public static final String QUEUE_A = "QA";public static final String QUEUE_B = "QB";public static final String Y_DEAD_LETTER_EXCHANGE = "Y";public static final String DEAD_LETTER_QUEUE = "QD";// 声明xExchange@Bean("xExchange")public DirectExchange xExchange() {return new DirectExchange(X_EXCHANGE);}// 声明yExchange@Bean("yExchange")public DirectExchange yExchange() {return new DirectExchange(Y_DEAD_LETTER_EXCHANGE);}// 声明队列A@Bean("queueA")public Queue queueA() {Map<String, Object> arguments = new HashMap<>();// 当前队列的死信交换机arguments.put("x-dead-letter-exchange", Y_DEAD_LETTER_EXCHANGE);// 当前队列的死信路由keyarguments.put("x-dead-letter-routing-key", "YD");// 声明队列的TTLarguments.put("x-message-ttl", 10000);return QueueBuilder.durable(QUEUE_A).withArguments(arguments).build();}// 声明队列A绑定交换机X@Beanpublic Binding queueABindingX(@Qualifier("queueA") Queue queueA,@Qualifier("xExchange")DirectExchange xExchange) {return BindingBuilder.bind(queueA).to(xExchange).with("XA");}// 声明队列B@Bean("queueB")public Queue queueB() {Map<String, Object> arguments = new HashMap<>();arguments.put("x-dead-letter-exchange", Y_DEAD_LETTER_EXCHANGE);// 当前队列的死信路由keyarguments.put("x-dead-letter-routing-key", "YD");// 声明队列的TTLarguments.put("x-message-ttl", 40000);return QueueBuilder.durable(QUEUE_B).withArguments(arguments).build();}// 声明队列B绑定交换机X@Beanpublic Binding queueBBindingX(@Qualifier("queueB") Queue queueB,@Qualifier("xExchange")DirectExchange xExchange) {return BindingBuilder.bind(queueB).to(xExchange).with("XB");}// 声明死信队列@Bean("queueD")public Queue queueD() {return new Queue(DEAD_LETTER_QUEUE);}@Bean// 声明死信队列 QD 绑定关系public Binding queuedBindingY(@Qualifier("queueD")Queue queueD,@Qualifier("yExchange")DirectExchange exchange) {return BindingBuilder.bind(queueD).to(exchange).with("YD");}}

(三)消息生产者

    @GetMapping("/sendMsg/{message}")public void sendMsg(@PathVariable String message) {log.info("当前时间是{},发送一条信息给两个 TTL 队列:{}", new Date().toString(), message);rabbitTemplate.convertAndSend("X", "XA", "消息来自ttl为10s的队列" + message);rabbitTemplate.convertAndSend("X", "XB", "消息来自ttl为40s的队列" + message);}

(四)消息消费者 

@Component
@Slf4j
public class DeadLetterQueueConsumer {@RabbitListener(queues = "QD")public void receiveD(Message message, Channel channel) throws IOException {String msg = new String(message.getBody());log.info("当前时间:{},收到死信队列信息{}", new Date().toString(), msg);}
}

发起一个请求 http://localhost:8080/ttl/sendMsg/嘻嘻嘻 

 

 

第一条消息在 10S 后变成了死信消息,然后被消费者消费掉,第二条消息在 40S 之后变成了死信消息,然后被消费掉,这样一个延时队列就打造完成了。
不过,如果这样使用的话,岂不是每增加一个新的时间需求,就要新增一个队列,这里只有 10S 40S 两个时间选项,如果需要一个小时后处理,那么就需要增加 TTL 为一个小时的队列,如果是预定会议室然后提前通知这样的场景,岂不是要增加无数个队列才能满足需求?

六、延迟队列优化

(一)代码架构图

在这里新增了一个队列 QC,绑定关系如下,该队列不设置 TTL 时间,而是由生产者设置过期时间

 

(二)配置文件类

@Configuration
public class TtlQueueConfig {public static final String X_EXCHANGE = "X";public static final String QUEUE_A = "QA";public static final String QUEUE_B = "QB";public static final String Y_DEAD_LETTER_EXCHANGE = "Y";public static final String DEAD_LETTER_QUEUE = "QD";public static final String QUEUE_C = "QC";// 声明xExchange@Bean("xExchange")public DirectExchange xExchange() {return new DirectExchange(X_EXCHANGE);}// 声明yExchange@Bean("yExchange")public DirectExchange yExchange() {return new DirectExchange(Y_DEAD_LETTER_EXCHANGE);}// 声明队列A@Bean("queueA")public Queue queueA() {Map<String, Object> arguments = new HashMap<>();// 当前队列的死信交换机arguments.put("x-dead-letter-exchange", Y_DEAD_LETTER_EXCHANGE);// 当前队列的死信路由keyarguments.put("x-dead-letter-routing-key", "YD");// 声明队列的TTLarguments.put("x-message-ttl", 10000);return QueueBuilder.durable(QUEUE_A).withArguments(arguments).build();}// 声明队列A绑定交换机X@Beanpublic Binding queueABindingX(@Qualifier("queueA") Queue queueA,@Qualifier("xExchange")DirectExchange xExchange) {return BindingBuilder.bind(queueA).to(xExchange).with("XA");}// 声明队列B@Bean("queueB")public Queue queueB() {Map<String, Object> arguments = new HashMap<>();arguments.put("x-dead-letter-exchange", Y_DEAD_LETTER_EXCHANGE);// 当前队列的死信路由keyarguments.put("x-dead-letter-routing-key", "YD");// 声明队列的TTLarguments.put("x-message-ttl", 40000);return QueueBuilder.durable(QUEUE_B).withArguments(arguments).build();}// 声明队列B绑定交换机X@Beanpublic Binding queueBBindingX(@Qualifier("queueB") Queue queueB,@Qualifier("xExchange")DirectExchange xExchange) {return BindingBuilder.bind(queueB).to(xExchange).with("XB");}// 声明队列C@Bean("queueC")public Queue queueC() {Map<String, Object> arguments = new HashMap<>();arguments.put("x-dead-letter-exchange", Y_DEAD_LETTER_EXCHANGE);// 当前队列的死信路由keyarguments.put("x-dead-letter-routing-key", "YD");return QueueBuilder.durable(QUEUE_C).withArguments(arguments).build();}// 声明队列C绑定交换机X@Beanpublic Binding queueCBindingX(@Qualifier("queueC") Queue queueC,@Qualifier("xExchange")DirectExchange xExchange) {return BindingBuilder.bind(queueC).to(xExchange).with("XC");}// 声明死信队列@Bean("queueD")public Queue queueD() {return new Queue(DEAD_LETTER_QUEUE);}@Bean// 声明死信队列 QD 绑定关系public Binding queuedBindingY(@Qualifier("queueD")Queue queueD,@Qualifier("yExchange")DirectExchange exchange) {return BindingBuilder.bind(queueD).to(exchange).with("YD");}}

(三)消息生产者

    @GetMapping("/sendExpirationMsg/{message}/{ttl}")public void sendMsg(@PathVariable String message, @PathVariable String ttl) {log.info("当前时间是{},发送一条过期信息给两个 TTL 队列:{}", new Date().toString(), message);rabbitTemplate.convertAndSend("X", "XC", message, msg -> {msg.getMessageProperties().setExpiration(ttl);return msg;});}

发起请求
http://localhost:8080/ttl/sendExpirationMsg/你好 1/20000
http://localhost:8080/ttl/sendExpirationMsg/你好 2/2000

看起来似乎没什么问题,但是在最开始的时候,就介绍过如果使用在消息属性上设置 TTL 的方式,消息可能并不会按时“死亡“,因为 RabbitMQ 只会检查第一个消息是否过期,如果过期则丢到死信队列,如果第一个消息的延时时长很长,而第二个消息的延时时长很短,第二个消息并不会优先得到执行

 

七、Rabbitmq 插件实现延迟队列

关于插件的安装可以查看这篇文章Docker安装RabbitMq延迟队列插件

 

(一)代码架构图

在这里新增了一个队列 delayed.queue,一个自定义交换机 delayed.exchange,绑定关系如下:  

 

(二)配置文件类

在我们自定义的交换机中,这是一种新的交换类型,该类型消息支持延迟投递机制 消息传递后并
不会立即投递到目标队列中,而是存储在 mnesia(一个分布式数据系统)表中,当达到投递时间时,才投递到目标队列中。

(三)消息生产者

/** 基于插件的延迟队列和延迟交换机*/
@Configuration
public class DelayedQueueConfig {public static final String DELAYED_QUEUE_NAME = "delayed.queue";public static final String DELAYED_EXCHANGE_NAME = "delayed.exchange";public static final String DELAYED_ROUTING_KEY = "delayed.routingkey";// 声明队列@Beanpublic Queue delayedQueue() {return new Queue(DELAYED_QUEUE_NAME);}// 声明自定义交换机@Beanpublic CustomExchange delayedExchange() {Map<String, Object> args = new HashMap<>();args.put("x-delayed-type", "direct");return new CustomExchange(DELAYED_EXCHANGE_NAME, "x-delayed-message", true, false, args);}// 声明队列和延迟交换机的绑定@Beanpublic Binding bindingDelayedQueue(@Qualifier("delayedQueue")Queue delayedQueue,@Qualifier("delayedExchange")CustomExchange exchange) {return BindingBuilder.bind(delayedQueue).to(exchange).with(DELAYED_ROUTING_KEY).noargs();}
}

(四)消息消费者

@Component
@Slf4j
public class DelayedQueueConsumer {@RabbitListener(queues = DelayedQueueConfig.DELAYED_QUEUE_NAME)public void receiveDelayedQueue(String message) {log.info("当前时间:{}, 接收到消息: {}", new Date().toString(), message);}
}
发起请求:
http://localhost:8080/ttl/sendDelayMsg/come on baby1/20000
http://localhost:8080/ttl/sendDelayMsg/come on baby2/2000

第二个消息被先消费掉了,符合预期

八、总结

延时队列在需要延时处理的场景下非常有用,使用 RabbitMQ 来实现延时队列可以很好的利用
RabbitMQ 的特性,如:消息可靠发送、消息可靠投递、死信队列来保障消息至少被消费一次以及未被正确处理的消息不会被丢弃。另外,通过 RabbitMQ 集群的特性,可以很好的解决单点故障问题,不会因为单个节点挂掉导致延时队列不可用或者消息丢失。
当然,延时队列还有很多其它选择,比如利用 Java DelayQueue,利用 Redis zset,利用 Quartz或者利用 kafka 的时间轮,这些方式各有特点,看需要适用的场景。

相关文章:

RabbitMQ延迟队列

目录 一、概念 二、使用场景 三、RabbitMQ 中的 TTL &#xff08;一&#xff09;队列设置 TTL &#xff08;二&#xff09;消息设置 TTL &#xff08;三&#xff09;两者的区别 四、整合SpringBoot实现延迟队列 &#xff08;一&#xff09;创建项目 &#xff08;二&am…...

Java中常用的七种队列你了解多少?

文章目录Java中常用的七种队列你了解多少?ArrayBlockingQueue队列如何使用&#xff1f;添加元素到队列获取队列中的元素遍历队列LinkedBlockingQueue队列如何使用&#xff1f;1. 创建SynchronousQueue对象2. 添加元素到队列3. 获取队列中的元素4. 遍历队列SynchronousQueue队列…...

<Java获取时间日期工具类>常见八种场景(一)

一:自定义时间日期工具类常用的八种方式&#xff08;整理&#xff09;: 0&#xff0c;getTimeSecondNum&#xff1a;时间日期转成秒数&#xff0c;常用于大小比较 1&#xff0c;getLastYearMonthLastDay&#xff1a;获取去年当月最后一天的时间日期 2&#xff0c;getLastYearM…...

接上一篇 对多个模型环形旋转进行优化 指定旋转位置

using System.Collections; using System.Collections.Generic; using UnityEngine; using DG.Tweening; public class ModelAnimal : MonoBehaviour { //记录鼠标滑动 public Vector2 lastPos;//鼠标上次位置 Vector2 currPos;//鼠标当前位置 Vector2 offset;//两次位置的偏移…...

Unity中获取地形的法线

序之前&#xff0c;生成了地形图&#xff1a;(42条消息) 从灰度图到地形图_averagePerson的博客-CSDN博客那末&#xff0c;地形的法线贴图怎么获取&#xff1f;大概分为两个部分吧&#xff0c;先拿到法线数据&#xff0c;再画到纹理中去。关于法线计算Unity - Scripting API: M…...

模型解释性:PFI、PDP、ICE等包的用法

本篇主要介绍几种其他较常用的模型解释性方法。 1. Permutation Feature Importance(PFI) 1.1 算法原理 置换特征重要性(Permutation Feature Importance)的概念很简单&#xff0c;其衡量特征重要性的方法如下&#xff1a;计算特征改变后模型预测误差的增加。如果打乱该特征的…...

spring常见面试题(2023最新)

目录前言1.spring是什么2.spring的设计核心是什么3.IOC和AOP面试题4.spring的优点和缺点5.spring中bean的作用域6.spring中bean的注入方式7.BeanFactory 和 ApplicationContext有什么区别&#xff1f;8.循环依赖的情况&#xff0c;怎么解决&#xff1f;9.spring中单例Bean是线程…...

华为OD机试题,用 Java 解【压缩报文还原】问题

最近更新的博客 华为OD机试题,用 Java 解【停车场车辆统计】问题华为OD机试题,用 Java 解【字符串变换最小字符串】问题华为OD机试题,用 Java 解【计算最大乘积】问题华为OD机试题,用 Java 解【DNA 序列】问题华为OD机试 - 组成最大数(Java) | 机试题算法思路 【2023】使…...

机器学习-BM-FKNCN、BM-FKNN等分类器对比实验

目录 一、简介和环境准备 二、算法简介 2.1四种方法类&#xff1a; 2.1.1FKNN 2.1.2FKNCN 2.1.3BM-FKNN 2.1.3BM-FKNCN 2.2数据预处理 2.3输出视图 2.4调用各种方法看准确率 2.4.1BM-FKNCN 2.4.2BM-FKNN 2.4.3FKNCN 2.4.4FKNN 2.4.5KNN 一、简介和环境准备 k…...

ChatGPT火了,对话式人工智能还能干嘛?

身兼数职的ChatGPT      从2022火到了2023      连日来一直是各大平台的热议对象      其实除了写诗、敲代码、处理文档      以ChatGPT为代表的      对话式人工智能      还有更重要的工作要做      对话式AI与聊天机器人      相信大多数人…...

十一、操作数栈的特点(Operand Sstack)

1.每一个独立的栈帧中除了包含局部变量表以外&#xff0c;还包含一个后进先出的操作数栈&#xff0c;也可以称之为表达式栈。 2.操作数栈&#xff0c;在方法执行过程中&#xff0c;根据字节码指令&#xff0c;往栈中写入数据&#xff0c;或提取数据&#xff0c;即入栈&#xff…...

拆解瑞幸新用户激活流程,如何让用户“动”起来?

Aha时刻 一个产品的拉新环节,是多种方式并存的;新用户可能来自于商务搭建了新的渠道,运营策划了新的活动,企划发布了新的广告,销售谈下了新的客户,市场推广了新的群体,以及产品本身的口碑传播,功能更新带来的自然流量。 这是一个群策群力的环节,不同的团队背负不同的K…...

tkinter界面的TCP通信/开启线程等待接收数据

前言 用简洁的语言写一个可以与TCP客户端实时通信的界面。之前做了一个项目是要与PLC进行信息交互的界面&#xff0c;在测试的时候就利用TCP客户端来实验&#xff0c;文末会附上TCP客户端。本文分为三部分&#xff0c;第一部分是在界面向TCP发送数据&#xff0c;第二部分是接收…...

华为OD机试题,用 Java 解【任务混部】问题

最近更新的博客 华为OD机试题,用 Java 解【停车场车辆统计】问题华为OD机试题,用 Java 解【字符串变换最小字符串】问题华为OD机试题,用 Java 解【计算最大乘积】问题华为OD机试题,用 Java 解【DNA 序列】问题华为OD机试 - 组成最大数(Java) | 机试题算法思路 【2023】使…...

看linux内核启动流程需要的汇编指令解释

一、指令 0.MRS 和MSR MRS 指令: 对状态寄存器CPSR和SPSR进行读操作。 MSR指令: 对状态寄存器CPSR和SPSR进行写操作。 1.adrp adrp x0, boot_args把boot_args的页基地址提取出来&#xff0c;放到x0中。 2.stp stp x21, x1, [x0]将 x21, x1 的值存入 x0寄存器记录的地址中…...

【巨人的肩膀】JAVA面试总结(二)

1、&#x1f4aa; 目录1、&#x1f4aa;1.0、什么是面向对象1.1、JDK、JRE、JVM之间的区别1.2、什么是字节码1.3、hashCode()与equals()之间的联系1.4、String、StringBuffer、StringBuilder的区别1.5、和equals方法的区别1.6、重载和重写的区别1.7、List和Set的区别1.8、Array…...

【网络安全入门】零基础小白必看!!!

看到很多小伙伴都想学习 网络安全 &#xff0c;让自己掌握更多的 技能&#xff0c;但是学习兴趣有了&#xff0c;却发现自己不知道哪里有 学习资源◇瞬间兴致全无&#xff01;◇ &#x1f604;在线找人要资料太卑微&#xff0c;自己上网下载又发现要收费0 &#x1f643;差点当…...

字节前端经典面试题(附答案)

有哪些可能引起前端安全的问题? 跨站脚本 (Cross-Site Scripting, XSS): ⼀种代码注⼊⽅式, 为了与 CSS 区分所以被称作 XSS。早期常⻅于⽹络论坛, 起因是⽹站没有对⽤户的输⼊进⾏严格的限制, 使得攻击者可以将脚本上传到帖⼦让其他⼈浏览到有恶意脚本的⻚⾯, 其注⼊⽅式很简…...

数据库管理工具的使用

目录 摘要 一、Navicat是什么&#xff1f; 二、使用步骤 1.如何下载与安装 2.如何连接远程数据库 总结 摘要 本文主要介绍数据库管理工具的使用 一、Navicat是什么&#xff1f; 它是一款数据库管理工具&#xff0c;将此工具连接数据库,你可以从中看到各种数据库的详细…...

让马斯克反悔的毫米波雷达,被国产雷达头部厂商木牛科技迭代到了5D时代

近日&#xff0c;特斯拉或将在其HW4.0硬件系统配置一枚高精度4D毫米波雷达的消息在外网刷屏。据分析&#xff0c;“纯视觉”信仰者马斯克之所以做出这样的决定&#xff0c;一方面是减配了雷达的特斯拉自动驾驶&#xff0c;表现不尽如人意&#xff1b;另一方面也跟毫米波雷达的技…...

MaxWell原理概述

文章目录1.MaxWell概述2.Maxwell输出数据格式3.Maxwell原理3.1 MySQL二进制日志3.2 MySQL主从复制1.MaxWell概述 Maxwell 是由美国Zendesk公司开源&#xff0c;用Java编写的MySQL变更数据抓取软件。它会实时监控Mysql数据库的数据变更操作&#xff08;包括insert、update、dele…...

电子技术——AB类输出阶

电子技术——AB类输出阶 原理 交越失真可以通过通过一个较小的偏置电流解除&#xff0c;如下图&#xff1a; QNQ_NQN​ 和 QPQ_PQP​ 的基极之间存在偏置电压 VBBV_{BB}VBB​ 。对于完美匹配的晶体管&#xff0c;当 vI0v_I 0vI​0 的时候&#xff0c;此时 vO0v_O 0vO​0 。每…...

Archlinux个人安装流程

操作环境&#xff1a; 时间&#xff1a;2023-02-17 电脑型号&#xff1a;联想拯救者R720 cpu&#xff1a;Intel Core i5-7300HQ 4x 3.5GHz gpu&#xff1a;NVIDIA GeForce GTX 1050 Ti 安装系统&#xff1a; 1.下载镜像&#xff1a; 请访问https://archlinux.org/查找镜…...

【Autoware】2小时安装Autoware1.13(保姆级教程)

前言&#xff1a;ROS的出现使得机器人软件开发更加快速和模块化&#xff0c;在此基础上&#xff0c;Autoware.ai开源项目可以让我们很容易地将一套完整的自动驾驶软件部署到我们的测试车辆上&#xff0c;并见证它跑起来&#xff01; 文章目录1.Autoware简介2.电脑软硬件配置要求…...

JVM 堆内存模型

方法区和永久代的关系 方法区与 Java 堆一样&#xff0c;是各个线程共享的内存区域&#xff0c;它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。虽然 Java 虚拟机规范把方法区描述为堆的一个逻辑部分&#xff0c;但是它却有一个别名叫做 N…...

linux-中断下半部

引用preempt宋宝华&#xff1a; 是谁关闭了Linux抢占&#xff0c;而抢占又关闭了谁&#xff1f;Linux用户抢占和内核抢占详解(概念, 实现和触发时机)--Linux进程的管理与调度(二十&#xff09;内核抢占实现(preempt)Linux中的preempt_count - 知乎 (zhihu.com)linux 中断子系统…...

SpringMVC源码:HandlerMapping加载1

参考资料&#xff1a; 《SpringMVC源码解析系列》 《SpringMVC源码分析》 《Spring MVC源码》 写在开头&#xff1a;本文为个人学习笔记&#xff0c;内容比较随意&#xff0c;夹杂个人理解&#xff0c;如有错误&#xff0c;欢迎指正。 前文&#xff1a; 《SpringMVC源码&a…...

【ArcGIS】12 投影

问题描述 在处理地理数据时,可能会遇到以下关于投影的问题: DEM缺少投影,提取流域会报错图层只有地理坐标系,没有投影坐标系,无法测量距离、计算面积等要素图层投影偏移量错误,与实际位置有偏差总之,投影对各种地理操作影响很大,有必要深入理解。 投影说明 在ArcGIS…...

【微信小程序-原生开发+TDesign】通用功能页封装——地点搜索(含腾讯地图开发key 的申请方法)

效果预览 核心技能点 调用腾讯地图官方的关键字地点搜索功能&#xff0c;详见官方文档 https://lbs.qq.com/miniProgram/jsSdk/jsSdkGuide/methodGetsuggestion 完整代码实现 地点输入框 <t-input value"{{placeInfo.title}}" bindtap"searchPlace" dis…...

h5: 打开手机上的某个app

1、android端&#xff1a;直接通过URL Scheme方式打开。2、ios端&#xff08;2种&#xff09;&#xff1a;&#xff08;1&#xff09;使用URL Scheme方式打开。&#xff08;2&#xff09;使用Universal link方式打开。3、Universal link方式使用注意事项&#xff1a;&#xff0…...

wordpress页面/营销管理培训课程培训班

1.在item级加触发器&#xff1a;key-listval&#xff1a;calendar.show; 2.修改该item属性&#xff1a; list of values &#xff1a;选择&#xff1a;enable_list_lamp&#xff1b; list y position: 设置为2.&#xff08;随意&#xff09; 是否从list验证&#xff1a;设置为n…...

手机网站免费做推广/百度客服中心

负margin理论&#xff1a; 何谓参考线&#xff1f;参考线就是 margin移动的基准点&#xff0c;此基准点相对于box(自身)是静止的。而margin的数值&#xff0c;就是box相对于参考线的位移量。 一个完整的margin属性是这么写的margin: top right bottom left;(eg: margin:10px 20…...

江苏网站建设要多少钱/网络营销推广专员

在以前&#xff0c;作为一个刚开始使用Python的开发者&#xff0c;我时常为布设一个有效的开发环境感到困扰。找到一套自己能顺畅使用的环境且为此培养一个正确的习惯是很困难的。 之前我一直没有意识到这些事情对我的工作效率影响有很大的影响&#xff0c;我甚至不知道一些我现…...

遵义做百度网站一年多少钱/南宁seo优化公司

来自 http://bbs.ldci.com.cn/read.php?tid-5501.html 记录一下 很多朋友希望在体验或学习iphone开发&#xff0c;但是iphone开发环境一般需要 安装在mac计算机下mac os中。 这给许多朋友带来了额外成本投入。网上已经有各种破解方法&#xff0c;在非苹果电脑上安装iphone开发…...

成都网站建设门户/线上平台推广方式

解决jQuery和其他库的冲突 当把jQuery和其他JavaScript库&#xff08;例如Prototype、MooTools或YUI&#xff09;一起使用时 <script> jQuery.noConflict();//将变量$的控制权让渡给prototype.js jQuery(function ($) {//使用jQuery设定页面加载时执行的函数 $("p&q…...

比较好的网站设计公司/如何制作一个网页链接

3、使用JavaScript引擎执行代码&#xff1a;JavaScript引擎的选择 iOS中可以使用系统自带的JavaScriptCore框架执行。Android中可以使用Rhino作为执行引擎&#xff0c;Rhino 是一种使用 Java 语言编写的 JavaScript 的开源实现&#xff0c;原先由Mozilla开发&#xff0c;现在被…...