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

【MQ篇】RabbitMQ之死信交换机!

在这里插入图片描述

目录

    • 引言:消息不死,只是变成死信?
    • 初识死信交换机:死信从哪来?DLX 干啥的?
      • 什么是死信?
      • 什么是死信交换机 (DLX)?
      • 死信的旅程:如何从队列到达 DLX 并被路由?🗺️
      • 死信交换机的使用场景总结 📜
    • TTL:让消息“过期”变死信 🕰️
      • 延迟队列:DLX + TTL 的“神仙组合” ✨📦⏳
      • DLX + TTL 实现延迟队列的代码配置(简要回顾)
      • RabbitMQ 官方 Delay Exchange 插件:更原生的延迟方案!
    • 总结:死信、TTL 与延迟队列 📜

🌟我的其他文章也讲解的比较有趣😁,如果喜欢博主的讲解方式,可以多多支持一下,感谢🤗!

🌟了解 MQ 请看 : 【MQ篇】初识MQ!

其他优质专栏: 【🎇SpringBoot】【🎉多线程】【🎨Redis】【✨设计模式专栏(已完结)】…等

如果喜欢作者的讲解方式,可以点赞收藏加关注,你的支持就是我的动力
✨更多文章请看个人主页: 码熔burning

引言:消息不死,只是变成死信?

朋友们!👋 咱们之前聊了 RabbitMQ 消息的可靠传输,确保消息能从生产者安全到达队列,不丢不失。但是,消息进了队列,就万事大吉了吗?图样图森破!🙅‍♀️ 消息在队列里可能会遇到各种“意外”,导致它无法被正常消费。比如:

  • 消费者处理不了,直接跟你“撂挑子”拒绝了!
  • 消息在队列里待太久,过期了!
  • 队列消息爆满了,新来的消息没地儿去,老消息就被挤掉了!

这些“命运多舛”的消息,RabbitMQ 给它们起了一个特别的名字——死信(Dead Letter)!👻✉️

那么问题来了,这些“死掉”的消息,RabbitMQ 会怎么处理呢?直接丢进回收站吗?当然不是(除非你没配置好)!对于重要的消息,每一条都不能轻易放弃!这时候,就要请出咱们今天的主角——死信交换机(Dead Letter Exchange - DLX) 登场了!它就像 RabbitMQ 里的“问题包裹回收中心”或者“死信中转站”,专门负责接收和处理这些来自“五湖四海”的死信!📦➡️💀➡️🔄

初识死信交换机:死信从哪来?DLX 干啥的?

什么是死信?

当一个队列中的消息满足下列情况之一时,可以成为死信(dead letter):

  • 消费者使用 basic.rejectbasic.nack 声明消费失败,并且消息的 requeue 参数设置为 false。这是最常见的主动制造死信的方式!“我不要这烫手山芋,你也别再发给我了,按死信处理吧!” 👋❌
  • 消息是一个过期消息,超时无人消费。消息或者它所在的队列设置了存活时间(TTL),时间到了还没被消费,就“自然死亡”了。🕰️👻
  • 要投递的队列消息满了,无法投递。队列像个仓库,容量有限,满了再来货,最老的可能被挤压“致死”。📏💀

我将用图片来展示了消息被消费者拒绝 (requeue=false) 后变成死信的过程:

在这里插入图片描述

什么是死信交换机 (DLX)?

DLX 并不是 RabbitMQ 里一种全新的交换机类型。它就是一个普通的交换机(可以是 Direct、Topic 或 Fanout),只不过它被某个普通队列指定为了接收死信的“专属通道”

如果一个包含死信的队列(比如 simple.queue)配置了 dead-letter-exchange 属性,指定了一个交换机(比如 dl.direct),那么队列中的死信就不会被丢弃,而是投递到这个指定的交换机中。这个被指定的交换机,就是死信交换机 (DLX)。

在这里插入图片描述

如果这个死信交换机也绑定了其他的队列,那么这些死信最终会进入这些队列,等待后续处理:

在这里插入图片描述

DLX 的核心作用: 就是作为一个“中转站”,收集各种原因产生的死信,并根据路由规则把它们发往最终的处理目的地(比如专门存放死信的队列、用于延迟重试的队列等)。

死信的旅程:如何从队列到达 DLX 并被路由?🗺️

队列将死信投递给死信交换机时,必须知道两个信息:死信交换机名称 和 死信交换机与死信队列绑定的 RoutingKey。这正是死信路由的关键所在!

  1. 指定 DLX 名称:普通队列声明时,通过 arguments 参数设置 x-dead-letter-exchange 来指定死信要去的 DLX 名称。

    // QueueBuilder.durable("simple.queue") // 指定队列名称
    //   .deadLetterExchange("dl.direct") // ⭐ 这里指定死信交换机名称 ⭐
    //   .build();
    

    这就是告诉 RabbitMQ,“我的死信都送去 dl.direct !”

  2. 死信的路由键: 当消息变成死信投递到 DLX 时,它需要一个路由键才能被 DLX 正确路由。这个路由键默认是原消息发送时的路由键。例如,原消息是发往 order.exchange,路由键是 "create",那么它变成死信后,默认会带着 "create" 这个路由键发往 DLX。

    • 可选: 你也可以在普通队列声明时,通过 arguments 参数设置 x-dead-letter-routing-key指定死信的路由键,这样所有从这个队列出来的死信都会使用这个指定的路由键,覆盖掉原路由键。
  3. DLX 的绑定与路由: DLX 收到死信后,就像处理普通消息一样,根据自身的交换机类型和死信的路由键,查找匹配的绑定,将死信路由到与之绑定的队列(这就是“死信队列”, dl.queue 就是一个例子)。

    在这里插入图片描述

    (死信携带路由键到达 DLX,DLX 按绑定规则路由到死信队列)

完整的 Spring Boot 代码示例,演示了如何配置一个普通队列 (simple.queue),让它的死信进入指定的 DLX (dl.direct),然后这个 DLX 又绑定了一个专门接收死信的队列 (dl.queue):

// producer服务CommonConfig中定义死信交换机、死信队列的代码
package cn.itcast.mq.config; // 假设你的包名import org.springframework.amqp.core.Binding; //
import org.springframework.amqp.core.BindingBuilder; //
import org.springframework.amqp.core.DirectExchange; //
import org.springframework.amqp.core.Queue; //
import org.springframework.amqp.core.QueueBuilder; //
import org.springframework.context.annotation.Bean; //
import org.springframework.context.annotation.Configuration; //@Configuration //
public class CommonConfig { //// ⭐ 定义业务队列,并配置其死信发往 DLX ⭐@Beanpublic Queue simpleQueue(){System.out.println("🛠️ 定义业务队列,指定死信交换机"); // 添加日志return QueueBuilder.durable("simple.queue") // 指定队列名称,并持久化 ✅.deadLetterExchange("dl.direct") // ⭐ 配置死信交换机为 dl.direct ⭐.build();}// ⭐ 声明死信交换机 dl.direct ⭐// 这个交换机用来接收来自 simple.queue 的死信@Beanpublic DirectExchange dlExchange(){System.out.println("🛠️ 声明死信交换机 dl.direct"); // 添加日志return new DirectExchange("dl.direct", true, false); // 持久化 ✅}// ⭐ 声明存储死信的队列 dl.queue ⭐// 这个队列绑定到 dl.direct 接收死信@Beanpublic Queue dlQueue(){System.out.println("🛠️ 声明存储死信的队列 dl.queue"); // 添加日志return new Queue("dl.queue", true); // 持久化 ✅}// ⭐ 将死信队列 dl.queue 与 死信交换机 dl.direct 绑定 ⭐// 绑定键要和从 simple.queue 出来的死信路由键匹配 (simple.queue 没有指定 deadLetterRoutingKey, 默认使用原路由键)// 假设原消息发送到 simple.queue 时使用的路由键是 "dl"@Beanpublic Binding dlBinding(){System.out.println("🛠️ 将死信队列 dl.queue 与 死信交换机 dl.direct 绑定,路由键为 'dl'"); // 添加日志return BindingBuilder.bind(dlQueue()).to(dlExchange()).with("dl"); // ⭐ 绑定键 "dl" ⭐}
}

注意:如果你之前已经用 @Bean@RabbitListener 声明过 simple.queue 队列且没有指定 deadLetterExchange 属性,现在又用同样的名字多加了这个属性来声明,启动时会因为队列属性冲突而报错。你需要先删除 RabbitMQ 中的旧队列再启动应用。

死信交换机的使用场景总结 📜

  • 如果队列绑定了死信交换机,死信会投递到死信交换机。这是机制本身。
  • 可以利用死信交换机收集所有消费者处理失败的消息(死信),交由人工处理,进一步提高消息队列的可靠性。这是最直接的用途,创建一个专门的 DLQ,把所有失败消息都导进去,方便运维人员查看和处理。

除了提到的收集失败消息用于人工处理,死信交换机还有一个更重要、更常见的应用场景,那就是实现延迟队列和延迟重试!📦⏳ 这就引出了后面详细介绍的 TTL。

TTL:让消息“过期”变死信 🕰️

TTL (Time To Live) 就像消息的“生命倒计时”。一个队列中的消息如果超时未被消费,就会变为死信。超时的方式有两种:

  1. 消息所在的队列设置了超时时间: 在队列声明时配置 x-message-ttl 属性。进入这个队列的消息,如果超过队列设定的 TTL 时间还没被消费,就会死掉。

    // RabbitConfig.java
    @Bean
    public Queue ttlQueue(){System.out.println("🛠️ 声明一个带 TTL 的队列"); // 添加日志return QueueBuilder.durable("ttl.queue") // 持久化.ttl(10000) // ⭐ 设置队列消息的 TTL,10 秒 (10000 毫秒) ⭐.deadLetterExchange("dl.ttl.direct") // ⭐ 这个队列的死信发往 dl.ttl.direct ⭐.build();
    }
    // 这个队列的死信交换机是 dl.ttl.direct,你需要定义它并绑定接收死信的队列
    // @Bean public DirectExchange dlTtlExchange() { ... }
    // @Bean public Queue dlTtlQueue() { ... }
    // @Bean public Binding dlTtlBinding(...) { ... }
    
  2. 消息本身设置了超时时间: 在发送消息时给消息设置 expiration 属性。消息进入队列后,如果它本身的过期时间先于队列的 TTL 到期,或者队列没有设置 TTL,消息也会死掉。发送时设置消息 TTL 的代码示例:

    // 发送消息时设置 TTL 的代码
    @Test // 这是一个测试方法
    public void testTTLMsg() {System.out.println("📨 正在发送一条带 TTL 的消息"); // 添加日志// 创建消息Message message = MessageBuilder.withBody("hello, ttl message".getBytes(StandardCharsets.UTF_8)).setExpiration("5000") // ⭐ 设置消息本身的 TTL,5 秒 (5000 毫秒) ⭐.build();// 消息ID,需要封装到CorrelationData中CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());// 发送消息到 ttl.direct 交换机,路由键 "ttl"rabbitTemplate.convertAndSend("ttl.direct", "ttl", message, correlationData);log.debug("发送消息成功");
    }
    

    注意: 当队列和消息都设置了 TTL 时,两者之间 TTL 值小的那个会生效,先到期的那个会让消息变成死信。

延迟队列:DLX + TTL 的“神仙组合” ✨📦⏳

利用 TTL 让消息过期变成死信,再利用死信交换机把死信路由到其他地方,就实现了消息发出后不是立即被消费,而是延迟一段时间后才被处理的效果!这种模式就称为延迟队列 (Delay Queue) 模式。

延迟队列的经典场景:延迟发送短信、用户下单 15 分钟未支付自动取消订单、预约会议 20 分钟后通知参会人员等。

DLX + TTL 实现延迟队列的原理:

  1. 生产者发送一个需要延迟的消息到业务交换机,消息路由到业务队列
  2. 业务队列被配置了死信交换机 x-dead-letter-exchange 指向 DLX
  3. 消息进入业务队列后,因为我们最终想要它延迟消费,所以它不能被立即消费。它需要变成死信!这里最常用的是利用 TTL
  4. 给业务队列或消息设置 TTL。消息在业务队列里等待 TTL 时间。⏰
  5. TTL 到期,消息变成死信。
  6. 因为业务队列配置了 DLX,死信被发送到 DLX。💀➡️
  7. DLX 绑定了一个新的队列,这个队列是真正的延迟队列。这个延迟队列没有消费者监听!它的唯一作用就是 “中转”和“等待”
  8. DLX 把死信路由到这个延迟队列
  9. 消息在这个延迟队列里等待。关键点来了! 这个延迟队列也要配置 x-message-ttl,并且这个 TTL 值就是你想要的延迟时间!⏳
  10. 消息在延迟队列里等待 TTL 时间到期后,再次变成死信。
  11. 这个延迟队列也要配置 x-dead-letter-exchange,并且,它把死信发回原来的业务交换机!🤯
  12. 业务交换机收到消息,再次把它路由回原来的业务队列
  13. 消费者监听的是原来的业务队列,于是它就收到了这条“延迟”后回来的消息!🎉

通过这个流程,消息就像在业务队列和“中转+等待”队列之间绕了个圈,成功实现了延迟消费。

DLX + TTL 实现延迟队列的代码配置(简要回顾)

你需要定义:

  • 业务交换机和业务队列: 业务队列配置 x-dead-letter-exchange 指向你的 DLX。
  • 死信交换机 (DLX): 一个普通交换机。
  • 延迟队列: 配置 x-message-ttl (延迟时间) 和 x-dead-letter-exchange 指向业务交换机。
  • 绑定: 将延迟队列绑定到 DLX,绑定键匹配业务队列死信的路由键。

这样,发送到业务队列的消息,如果设置了小于业务队列 TTL 的 TTL(或者业务队列没有 TTL),就会在业务队列里变成死信 -> 进入 DLX -> 进入延迟队列 -> 在延迟队列里等待 TTL -> 变成死信 -> 发回业务交换机 -> 回到业务队列被消费。

RabbitMQ 官方 Delay Exchange 插件:更原生的延迟方案!

RabbitMQ 官方提供的 Delay Exchange 插件!👏 如果你的 RabbitMQ 版本支持,使用这个插件实现延迟功能会更简单粗暴,不需要 DLX + TTL 这种“曲线救国”的方式。

  • 原理: 声明一个类型为 x-delayed-message 并设置 delayed = true 的交换机。当你发送消息到这个交换机时,消息会先被插件接收并持久化,然后读取消息头的 x-delay 属性作为延迟时间。时间到期后,插件会模拟一次消息投递,把消息发送到该交换机绑定的队列。

  • 使用方式:

    1. 安装 Delay Exchange 插件(自行查找安装教程)。
    2. 声明一个交换机,类型可以是任意类型 (如 Direct),但必须添加 delayed = true 属性。基于注解 @Exchange(name = "delay.direct", delayed = "true") 或者基于 Bean 配置都可以。
    3. 发送消息时,在消息头里添加 x-delay 属性,值就是你想要的延迟时间(毫秒)。发送消息的代码示例:
    // 发送延迟消息的示例
    @Test // 测试方法
    public void testDelayedMsg() {System.out.println("📨 正在发送一条使用 Delay Exchange 插件的延迟消息"); // 添加日志// 创建消息Message message = MessageBuilder.withBody("hello, delay message".getBytes(StandardCharsets.UTF_8)).setHeader("x-delay",10000) // ⭐ 在消息头设置 x-delay,指定延迟时间 10 秒 ⭐.build();// 消息ID,需要封装到CorrelationData中CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());// 发送消息到延迟交换机 delay.direct,路由键 "delay"rabbitTemplate.convertAndSend("delay.direct", "delay", message, correlationData);log.debug("发送消息成功");
    }
    

    使用 Delay Exchange 插件,流程更直观:消息 -> 延迟交换机 (等待) -> 延迟时间到 -> 发往绑定队列 -> 被消费者消费。省去了 DLX 和额外队列的周转。

总结:死信、TTL 与延迟队列 📜

我们可以更全面地理解死信、TTL 和延迟队列:

什么样的消息会成为死信?

  • 消息被消费者 reject 或者 nackrequeue=false
  • 消息超时未消费(消息或队列 TTL 到期)。
  • 队列满了。

死信交换机的使用场景是什么?

  • 收集所有消费者处理失败的消息(死信),交由人工处理,提高可靠性。
  • 与 TTL 结合,实现消息的延迟队列功能。

消息超时的两种方式是?

  • 给队列设置 x-message-ttl 属性。
  • 给消息设置 expiration 属性。

如何实现发送一个消息 N 秒后消费者才收到消息? (使用 DLX + TTL 方案)

  1. 给消息的目标队列指定死信交换机 (x-dead-letter-exchange)。
  2. 声明一个延迟队列,设置 x-message-ttl 为 N 秒,并将其 x-dead-letter-exchange 指向原业务交换机
  3. 将这个延迟队列绑定到业务队列指定的死信交换机(绑定键匹配死信路由键)。
  4. 发送消息到业务队列,确保消息进入业务队列后不被立即消费(比如没有消费者或消费者收到后 NACK(false, false))。消息会在业务队列里因无人消费或被 NACK 变成死信,进入 DLX -> 进入延迟队列等待 N 秒 -> 过期变死信 -> 回到业务交换机 -> 回到业务队列被消费。

或者,更简单的方案是使用 RabbitMQ Delay Exchange 插件

  1. 安装插件。
  2. 声明一个 delayed = true 的交换机。
  3. 将消费者监听的队列绑定到这个延迟交换机。
  4. 发送消息到这个延迟交换机,并在消息头设置 x-delay 为 N 毫秒。

死信交换机是 RabbitMQ 处理异常消息、实现延迟重试和构建复杂工作流的核心组件。理解了它的工作原理和配置方式,你就掌握了 RabbitMQ 消息高级玩法的敲门砖!🔑🚪

希望这篇超详细的死信交换机“攻略”能帮助你彻底吃透它!😊🚀

了解RabbitMQ消息不丢的“三板斧”请看:
【MQ篇】RabbitMQ的生产者消息确认实战!
【MQ篇】RabbitMQ之消息持久化!
【MQ篇】RabbitMQ的消费者确认机制实战!
了解RabbitMQ消息失败重试请看:
【MQ篇】RabbitMQ之消费失败重试!

相关文章:

【MQ篇】RabbitMQ之死信交换机!

目录 引言:消息不死,只是变成死信?初识死信交换机:死信从哪来?DLX 干啥的?什么是死信?什么是死信交换机 (DLX)?死信的旅程:如何从队列到达 DLX 并被路由?&…...

CI/CD解决方案TeamCity在游戏开发中的应用价值与优势分析

TeamCity是用于游戏开发的最流行的CI/CD工具之一。从独立开发者到3A工作室和游戏发行商,各种规模的公司都在使用。无论您在制作流程中使用何种工具,TeamCity都支持您为任何的工作流程设置全面的构建-测试-发布管道。 TeamCity如何增强您的游戏开发工作流…...

泰迪杯实战案例超深度解析:运输车辆安全驾驶行为分析与安全评价系统设计

(第七届泰迪杯数据挖掘挑战赛C题特等奖案例解析) 一、案例背景与目标 1.1 应用场景与痛点 在道路运输行业,不良驾驶行为(如急加速、急减速、疲劳驾驶)是引发交通事故的主要诱因,占事故总量的70%以上。某运输企业通过车联网系统采集了450辆运输车辆的高频数据(每秒1条)…...

C++初阶-模板初阶

目录 1.泛型编程 2.函数模板 2.1函数模板概念 2.2实现函数模板 2.3模板的原理 2.4函数模板的实例化 2.4.1隐式实例化 2.4.2显式初始化 2.5模板参数的匹配原则 3.类模板 3.1类模板定义格式 3.2类模板的实例化 4.总结 1.泛型编程 对广泛的类型法写代码,我…...

计算机网络自顶向下思维导图

主要就是记录下自己做的1-6章的思维导图,内容包含了每章每节内的重点内容 可能又错别字以及错误,欢迎指出 需要注意使用的是第七版的书 第一章 第二章 第二章二 第三章 第四章 第五章 第六章...

机器学习-入门-线性模型(1)

机器学习-入门-线性模型(1) 文章目录 机器学习-入门-线性模型(1)3.1 线性回归3.2 最小二乘解3.3 多元线性回归 3.1 线性回归 f ( x i ) w x i b 使得 f ( x i ) ≃ y i f(x_i) wx_i b \quad \text{使得} \quad f(x_i) \simeq y_i f(xi​)wxi​b使得f(xi​)≃yi​ 离散属性…...

Spark-Streaming3

无状态转换操作与有状态转换操作 无状态转换操作: 无状态转换操作仅处理当前时间跨度内的数据。例如,设置的采集时间为三秒,则只处理这三秒内的数据。 有状态转换操作(UpdateStateByKey): 有状态转换操作可以跨批次处理数据。涉及…...

【Pandas】pandas DataFrame rfloordiv

Pandas2.2 DataFrame Binary operator functions 方法描述DataFrame.add(other)用于执行 DataFrame 与另一个对象(如 DataFrame、Series 或标量)的逐元素加法操作DataFrame.add(other[, axis, level, fill_value])用于执行 DataFrame 与另一个对象&…...

【Spark入门】Spark简介:分布式计算框架的演进与定位

目录 1 大数据计算框架的演进历程 1.1 Hadoop MapReduce:第一代分布式计算框架 1.2 Spark的诞生与革新 2 Spark的核心架构与优势 2.1 Spark架构概览 2.2 Spark的核心优势解析 3 Spark的适用场景与定位 3.1 典型应用场景 3.2 技术定位分析 4 Spark与Hadoop…...

基于ArcGIS的洪水淹没分析技术-洪水灾害普查、风险评估及淹没制图中的实践技术

洪水灾害是全球面临的主要自然灾害之一,对人类社会和自然环境造成巨大影响。准确的洪水淹没分析对于灾害预防、风险评估及应急响应至关重要。ArcGIS作为一款强大的地理信息系统软件,在洪水淹没分析领域具有显著优势。ArcGIS的洪水淹没分析主要依赖于其强…...

【数据可视化-38】基于Plotly得泰坦尼克号数据集的多维度可视化分析

🧑 博主简介:曾任某智慧城市类企业算法总监,目前在美国市场的物流公司从事高级算法工程师一职,深耕人工智能领域,精通python数据挖掘、可视化、机器学习等,发表过AI相关的专利并多次在AI类比赛中获奖。CSDN…...

数据库MySQL学习——day6(多表查询(JOIN)基础)

文章目录 1、关系型数据库中的表关系2、连接(JOIN)的基本概念3、INNER JOIN(内连接)3.1. 概念3.2. 语法结构 4、LEFT JOIN(左连接)4.1. 概念4.2. 语法结构 5、RIGHT JOIN(右连接)&am…...

Mysql如何高效的查询数据是否存在

文章目录 1. 三种方法2. 查询语句执行流程3. 三种方式对比 1. 三种方法 在业务中,我们有时候需要查询某个数据在数据表中是否存在,常见的方式有三种 SELECT COUNT(*) FORM tb_name WHERE conditionSELECT 1 FROM tb_name WHERE conditionSELECT EXISTS (SELECT 1 FROM tb_nam…...

MySQL快速入门篇---增删改查(下)

目录 一、修改(Update) 1.语法 2.示例 二、删除(Delete) 1.语法 2.示例 三、聚合函数 1.示例 1.1、COUNT 1.2、SUM 1.3、AVG 1.4、MAX 1.5、MIN 四、分组查询(GROUP BY) 1.语法 2.示例 …...

Mysql中隐式内连接和显式内连接的区别

1. 内连接(INNER JOIN) 内连接是数据库中一种常见的连接方式,用于从两个或多个表中返回满足连接条件的记录,即只返回两张表中匹配的行。 示例场景:有学生表(包含学生 ID 和姓名)和成绩表&…...

检测软件系统如何确保稳定运行并剖析本次检测报告?

检测软件系统,能及时找出问题,确保软件稳定运行,保障用户使用体验。下面会具体剖析本次检测报告。 检测概述 本次检测覆盖了系统性能、功能完整性等关键方面。它对软件整体状况做了严格评估。检测时对系统代码展开深度审查。还借助专业工具…...

【Office-Excel】单元格输入数据后自动填充单位

1.自定义设置单元格格式 例如我想输入数字10,回车确认后自动显示10kg。 右击单元格或者快捷键(Ctrl1),选择设置单元格格式,自定义格式输入: 0"kg"格式仍是数字,但是显示是10kg&…...

GAMES202-高质量实时渲染(Real-Time Shadows)

目录 Shadow MappingshadowMapping的问题shadow mapping背后的数学PCF(Percentage Closer Filtering)PCSS(Percentage closer soft shadows)VSSM(Variance Soft Shadow Mapping)优化步骤3优化步骤1SAT&…...

vue+neo4j+flask 音乐知识图谱推荐系统

文章结尾部分有CSDN官方提供的学长 联系方式名片 文章结尾部分有CSDN官方提供的学长 联系方式名片 关注B站,有好处! 编号: F027 架构: vueflaskneo4jmysql 亮点:协同过滤推荐算法知识图谱可视化 支持爬取音乐数据,数据超过3万条&…...

JavaScript 中 undefined 和 not defined 的区别

在 JavaScript 的调试过程中,你是否经常看到 undefined 却不知其来源?是否曾被 ReferenceError: xxx is not defined 的错误提示困扰?这两个看似相似的概念,实际上是 JavaScript 类型系统中最重要的分水岭。本文将带你拨开迷雾&am…...

设计一个新能源汽车控制系统开发框架,并提供一个符合ISO 26262标准的模块化设计方案。

今天,设计一个新能源汽车控制系统开发框架,并提供一个符合ISO 26262标准的模块化设计方案。以下为经过工业验证的技术方案: 一、系统架构设计 采用AUTOSAR Adaptive平台构建分布式系统,核心模块包括: 车辆控制单元(VC…...

基于STM32、HAL库的HX710A模数转换器ADC驱动程序设计

一、简介: HX710A是一款高精度24位模数转换器(ADC)芯片,专为电子秤和其他高精度测量应用设计。它通常与称重传感器(如应变片)配合使用,具有以下特点: 24位无失码精度 可编程增益:128或64 内置低噪声可编程放大器 片上稳压器,可直接为传感器供电 简单的数字接口(时钟+数据…...

python合并一个word段落中的run

在python-docx中,一个段落可以包含多个Run对象,每个Run对象可以具有不同的样式。如果你希望将一个段落中的所有Run对象合并为一个Run对象,同时保留所有文本内容,可以通过以下步骤实现: 合并Run对象的方法 遍历段落的…...

pytorch搭建并训练神经网络

#从小白开始学习人工智能# #学习笔记# 工具:pytorch 一、基础概念 1.神经网络是什么? 神经网络是人类受到生物神经细胞结构启发而研究出的算法体系。又称为人工神经网络(Artificial neural network) 最简版神经网络结构图&a…...

GCC 内建函数汇编展开详解

1. 引言 GNU 编译器集合(GCC)是广泛使用的开源编译器套件,支持多种编程语言,其中 C 语言编译器是其核心组件之一。在 C 语言编译过程中,GCC 不仅处理用户编写的标准 C 代码,还提供了一类特殊的函数——内建…...

iOS自定义电池电量显示控件 BatteryView 实现

iOS自定义电池视图:BatteryView 传送门:Android自定义电池电量显示控件 BatteryView 实现 在iOS开发中,自定义视图是提升用户体验的重要手段之一。本文将介绍如何通过Swift语言实现一个自定义的电池视图(BatteryView),并展示其功能和使用方法。 1. 功能概述 BatteryVi…...

LeetCode -- Flora -- edit 2025-04-27

1.接雨水 42. 接雨水 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。 示例 1: 输入:height [0,1,0,2,1,0,1,3,2,1,2,1] 输出:6 解释:上面是由数组 [0,1,…...

00-算法打卡-目录

1 数组 01-算法打卡-数组-二分查找-leetcode(704)-第一天-CSDN博客 02-算法打卡-数组-二分查找-leetcode(35)-第二天-CSDN博客 03-算法打卡-数组-二分查找-leetcode(34)-第三天_leetcode 34-CSDN博客 04-算法打卡-数组-二分查找-leetcode(69)-第四天-CSDN博客 05-算法打卡-数组…...

Vue2 与 Vue3 深度对比与技术解析

引言 Vue.js 是由尤雨溪创立的渐进式(progressive)JavaScript框架,自 2014 年发布以来,以其简单易用和灵活扩展性得到广泛应用。在 Vue2 的时代,它已经成为构建单页应用(SPA)和组件化开发的主流…...

Linux-UDP套接字编程

一.认识IP地址 IP 协议有两个版本, IPv4 和 IPv6. 我们之后凡是提到 IP 协议, 没有特殊说明的,默认都是指 IPv4。 IP 地址是在 IP 协议中, 用来标识网络中不同主机的地址;对于 IPv4 来说, IP 地址是一个 4 字节, 32 位的整数;我们通常也使用 "点分十进制" 的字符串表…...

tsconfig.json和tsconfig.node.json和tsconfig.app.json有什么区别

通过pnpm i vite 生成vue3项目时,会生成三个ts配置文件,分别是什么作用呢? 在Vue 3项目中,tsconfig.json、tsconfig.node.json和tsconfig.app.json是三个不同的TypeScript配置文件,它们分别用于不同的场景和目的。其中tsconfig.n…...

机器学习——Seaborn练习题

1、使用tips数据集,创建一个展示不同时间段(午餐/晚餐)账单总额分布的箱线图 import seaborn as sns import matplotlib.pyplot as plt import numpy as np import pandas as pdplt.rcParams["font.sans-serif"] ["SimHei"] plt.rcParams[&qu…...

Spring XML 外部实体(XXE)指南:示例和预防

什么是XXE? XML 文档遵循特定的标准。该标准强调了 XML 文档的构造方式,概述了有效 XML 文档与无效 XML 文档的区别等等。 该标准还指定了一个称为“实体”的术语。实体是某些内容的占位符。 实体可以是内部的,也可以是外部的(就像我们的情况一样)。 实体通过系统标识…...

C语言(3)—分支和循环

文章目录 一、程序的基本结构二、分支结构1. if语句2. if-else语句 三、关系与逻辑运算符1. 关系运算符2. 逻辑运算符 四、条件运算符(三目运算符)五、switch语句六、循环结构1. while循环2. for循环 七、循环控制语句1. break2. continue 八、循环嵌套九…...

【MCP】从一个天气查询服务带你了解MCP

1. 前言 这篇文章将通过一个集成高德天气查询的 MCP Server 用例,带你上手开发自己的 MCP Server ,文章将通过以下三种方式(自己编写 Client 端代码,使用 mcp-cli 自带页面,集成到 Claude 桌面版等)带你测试自己的 MC…...

【Leetcode 每日一题】3392. 统计符合条件长度为 3 的子数组数目

问题背景 给你一个整数数组 n u m s nums nums,请你返回长度为 3 3 3 的 子数组,满足第一个数和第三个数的和恰好为第二个数的一半。 子数组 指的是一个数组中连续 非空 的元素序列。 数据约束 3 ≤ n u m s . l e n g t h ≤ 100 3 \le nums.length…...

SALOME源码分析:Geomtry模块

本文分析SALOME Geometry模块。 一、核心组件 1.1 GeometryGUI 二、关键流程 三、插件 3.1 插件接口 GEOMPluginGUI定义了Geometry可以加载的插件接口。 3.2 插件列表 插件命令描述 BasicGUI BlocksGUI BooleanGUI BuildGUI DisplayGUI EntityGUI GenerationGUI GEOM…...

力扣HOT100之链表:23. 合并 K 个升序链表

这道题我是用最淳朴最简单的思路去做的,用一个while循环持续地将当前遍历到的最小值加入到合并链表中,while循环中使用一个for循环遍历整个指针数组,将其中的最小值和对应下标记录下来,并将其值加入到合并链表中,同时对…...

ArkTS 组件 通用事件 通用属性 速查表

ArkTS 组件 组件 通用事件 速查表 通用事件事件名称简要说明点击事件onClick(event: Callback<ClickEvent>, distanceThreshold: number): T相较于原有 onClick 接口&#xff0c;新增 distanceThreshold 参数作为点击事件移动阈值&#xff0c;当手指的移动距离超出所设…...

SOAP API 和 REST API

SOAP API 和 REST API 是两种主流的 Web 服务通信架构&#xff0c;它们在设计理念、数据格式、协议支持和应用场景上有显著差异。以下是两者的核心对比及典型应用场景&#xff1a; 1. 核心概念与设计哲学 特性SOAP APIREST API本质协议&#xff08;基于 XML 的标准化协议&…...

简单了解Java的I/O流机制与文件读写操作

一、理解Java的I/O流机制 字节流 Java中的字节流主要由 InputStream 和 OutputStream 这两个抽象类及其子类构成。字节流以字节&#xff08;byte&#xff09;为基本处理单元&#xff0c;适用于处理所有类型的数据&#xff0c;包括文本、图片、音频、视频等。 1. InputStream…...

PCIe 转 U.2 接双硬盘指南 - 超微(Supermicro)主板

前言 公司服务器空间不够想扩容&#xff0c;尝试折腾了下超微&#xff08;Supermicro&#xff09;服务器的 PCIe 转 U.2&#xff0c;踩了一点小坑&#xff0c;特地写下来给大家参考一下。 现在市面上 U.2 接口的企业级固态硬盘相对其他类型接口的固态硬盘 便宜很多 &#xff…...

【上位机——MFC】文档

相关类 CDocument提供了一个用于管理数据的类&#xff0c;封装了关于数据的管理(数据提取、数据转换、数据存储等)&#xff0c;并和视图类进行数据交互。 文档类使用 定义一个自己的文档类&#xff0c;派生自CDocument 程序的创建过程 1.利用框架类对象地址pFrame调用Load…...

JavaEE-多线程实战02

接上 多线程编程实战01 第三个多线程程序 package thread.test;//定义了一个叫MyThread3的类&#xff0c;实现了Runable接口,所以它必须重写run()方法 class MyThread3 implements Runnable {Overridepublic void run() {//线程执行的具体内容//进入一个无限循环&#xff0c;…...

计算机网络 | 应用层(6) -- 套接字编程

&#x1f493;个人主页&#xff1a;mooridy &#x1f493;专栏地址&#xff1a;《计算机网络&#xff1a;自顶向下方法》 大纲式阅读笔记_mooridy的博客-CSDN博客 &#x1f493;本博客内容为《计算机网络&#xff1a;自顶向下方法》第二章应用层第七节知识梳理 关注我&#x1f…...

基于大模型的急性肠套叠全流程预测与诊疗方案研究报告

目录 一、引言 1.1 研究背景与目的 1.2 研究意义与创新点 二、急性肠套叠概述 2.1 定义与分类 2.2 病因与发病机制 2.3 流行病学特征 三、大模型技术原理与应用现状 3.1 大模型基本原理 3.2 在医疗领域的应用案例 3.3 用于急性肠套叠预测的可行性分析 四、术前风险…...

游戏遭遇DDoS攻击如何快速止损?实战防御策略与应急响应指南

是不是很抽象 我自己画的 一、游戏DDoS攻击特征深度解析 游戏行业DDoS攻击呈现复合型特征&#xff0c;2023年监测数据显示&#xff0c;针对游戏服务器的攻击中&#xff0c;63%采用UDP反射放大HTTP慢速攻击组合&#xff0c;攻击峰值达3.2Tbps。攻击者利用游戏协议特性&#xff…...

Linux电源管理(2)_常规的电源管理的基本概念和软件架构

原文&#xff1a; Linux电源管理(2)_Generic PM之基本概念和软件架构 1. 前言 Linux系统中那些常规的电源管理手段&#xff0c;包括关机&#xff08;Power off&#xff09;、待机&#xff08;Standby or Hibernate&#xff09;、重启&#xff08;Reboot&#xff09;等。这些…...

回文链表力扣234

思路: 对于这个题同样的找出题目的要求 1.判断回文 那么我们思考一下判断回文的方法&#xff0c;对于字符串我们只需要翻转一下就行&#xff0c;但是这不是通用的方法&#xff0c;在思考一下&#xff0c;我们是不是可以用双指针&#xff0c;一个在前一个在后&#xff0c;向中…...

互联网的下一代脉搏:深入理解 QUIC 协议

互联网的下一代脉搏&#xff1a;深入理解 QUIC 协议 互联网是现代社会的基石&#xff0c;而数据在其中高效、安全地传输是其运转的关键。长期以来&#xff0c;传输层的 TCP&#xff08;传输控制协议&#xff09;一直是互联网的主力军。然而&#xff0c;随着互联网应用场景的日…...