RocketMQTemplate 实现消息发送

news2024/11/28 10:52:33

代码托管于gitee:easy-rocketmq

文章目录

    • 一、前置工作
    • 二、消费者
    • 三、生产者
      • 1. 普通消息
      • 2. 过滤消息
      • 3. 同步消息
      • 4. 延时消息
      • 5. 批量消息
      • 6. 异步消息
      • 7. 单向消息
      • 8. 顺序消息
      • 9. 事务消息
        • 概要
        • Demo
        • 源码解读

一、前置工作

1、导入依赖

<dependency>
    <groupId>org.apache.rocketmq</groupId>
    <artifactId>rocketmq-spring-boot-starter</artifactId>
    <version>2.1.1</version>
</dependency>

2、编写配置

rocketmq:
  name-server: 47.96.232.192:9876
  producer:
    # 生产组名
    group: demoGroup
    # 消息发送超时时间
    send-message-timeout: 3000
    # 消息体阈值,4k以上会压缩
    compress-message-body-threshold: 4096
    # 在同步模式下发送失败之前在内部执行的最大重试次数。
    retry-times-when-send-failed: 3
    # 在异步模式下发送失败之前在内部执行的最大重试次数。
    retry-times-when-send-async-failed: 3
    # 消息阈值,最大4MB,在 4KB 之内性能最佳
    max-message-size: 4096

二、消费者

实现RocketMQListener接口,使用 @RocketMQMessageListener 注册监听,需指定消费者组和Topic。

@Component
@RocketMQMessageListener(
        consumerGroup = "demo-consumer-group",  // consumerGroup:消费者组名
        topic = "Demo",                         // topic:订阅的主题
        selectorExpression = "*",               // selectorExpression:控制可以选择的消息,可以使用SelectorType.SQL92语法。设置为 * 时,表示全部。
        messageModel = MessageModel.CLUSTERING  // messageModel: 控制消息模式。MessageModel.CLUSTERING:负载均衡;MessageModel.BROADCASTING:广播模式
)
public class MqConsumerListener implements RocketMQListener<String> {

    @Override
    public void onMessage(String message) {
        System.out.println("消费消息-" + message);
    }
    
}

测试一下消费情况~

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XZp5iWqs-1677066712694)(RocketMQTemplate 实现消息发送.assets/image-20230215202513669.png)]

三、生产者

1. 普通消息

普通消息无返回值,只负责发送消息⽽不等待服务器回应且没有回调函数触发。

@Override
public void convertAndSend(D destination, Object payload) throws MessagingException {
   convertAndSend(destination, payload, (Map<String, Object>) null);
}

发送一个普通消息吧~

@SpringBootTest
class RocketmqTemplateDemoApplicationTests {

    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    /**
     * 普通消息无返回值,只负责发送消息⽽不等待服务器回应且没有回调函数触发
     *  - 参数一:topicName:tags,主题:标签,可单Topic不指定Tag
     *  - 参数二:消息体
     */
    @Test
    public void sendBaseMsg() {
        rocketMQTemplate.convertAndSend("Demo:base","普通消息测试");
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-THzerNj5-1677067369640)(RocketMQTemplate 实现消息发送.assets/image-20230215195854038.png)]

源码

接下来我们一步一步点进去~

在这里插入图片描述

此时我们发现其调用的最终调用了 doSend 方法,在其实现类RocketMQTemplate中调用了syncSend()方法,该方法以同步的方式发送消息并且返回值SendResult。但 doSend 方法的返回值类型是void,并不返回SendResult。

在这里插入图片描述

我们发现该syncSend()底层是调用了DefaultMQProducer的send方法,这里关于DefaultMQProducer就不做过多讲解了~

2. 过滤消息

convertAndSend还有另外一个可携带属性的重载方法,可以通过给消息携带属性的方式,消费者利用sql92的方式实现消息过滤~

@Override
public void convertAndSend(D destination, Object payload, @Nullable Map<String, Object> headers)
      throws MessagingException {

   convertAndSend(destination, payload, headers, null);
}

发送携带属性的消息吧~

发送若干条消息携带属性a,属性值分别为0~9。消费者消息过滤仅消费携带属性a且属性值在[6,9]范围内的(包含)

/**
 * 过滤消息
 */
@GetMapping("/filter")
public void sendFilterMsg() {
    for (int i = 0; i < 10; i++) {
        HashMap<String, Object> harder = new HashMap<>(1);
        harder.put("a", String.valueOf(i));
        rocketMQTemplate.convertAndSend("Demo:filter","过滤消息测试" + i, harder);
    }
}

通过sql92过滤消息

1、修改选择消息模式为 SelectorType.SQL92,默认模式是SelectorType.TAG。

selectorType = SelectorType.SQL92

2、编写过滤sql:

selectorExpression = "a BETWEEN 6 AND 9"
@Component
@RocketMQMessageListener(
        consumerGroup = "demo-consumer-group",      // consumerGroup:消费者组名
        topic = "Demo",                             // topic:订阅的主题
        selectorType = SelectorType.SQL92,          // selectorType:那种模式选择消息
        selectorExpression = "a BETWEEN 6 AND 9",   // selectorExpression:控制可以选择的消息,可以使用SelectorType.SQL92语法。设置为 * 时,表示全部。
        messageModel = MessageModel.CLUSTERING      // messageModel: 控制消息模式。MessageModel.CLUSTERING:负载均衡;MessageModel.BROADCASTING:广播模式
)
public class MqConsumerListener implements RocketMQListener<Object> {

    @Override
    public void onMessage(Object message) {
        System.out.println("消费消息-" + message);
    }

}

biu发送消息~
在这里插入图片描述

源码

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EJZwygeF-1677067561266)(RocketMQTemplate 实现消息发送.assets/image-20230216170539136.png)]

通过观看源码我们发现在封装RocketMQ消息时会将属性塞进消息头中,然后发送。在消费时监听器会从消息头中获取该属性过滤消息。

3. 同步消息

同步消息有返回值SendResult,等到消息发送成功后才算结束。

    /**
     * 同步消息有返回值SendResult,等到消息发送成功后才算结束。
     */
    @Test
    public void sendSyncMsg() {
        SendResult result = rocketMQTemplate.syncSend("Demo:sync", "同步消息测试");
        System.out.println(JSONObject.toJSONString(result));
    }

源码

public SendResult syncSend(String destination, Object payload) {
    return syncSend(destination, payload, producer.getSendMsgTimeout());
}

在第一节中我们已经看过其源码,底层是调用了DefaultMQProducer的send方法~


4. 延时消息

/**
 * 延时消息
 */
@Test
public void sendDelayMsg() {
    Message<String> msg = MessageBuilder.withPayload("延时消息测试").build();
    rocketMQTemplate.syncSend("Demo:delay", msg, 100, 3);
}

在RocketMQ中并不支持任意时间的延迟,需要设置几个固定的延时等级,从1s到2h分别对应着等级1到18:

// org/apache/rocketmq/store/config/MessageStoreConfig.java
private String messageDelayLevel = "1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h";

源码

  • destination:topicName:tags,主题:标签,可单Topic不指定Tag
  • message:org.springframework.messaging.Message具有标题和正文的通用消息实体
  • timeout:消息发送时间域
  • delayLevel:延迟消息的级别

在这里插入图片描述

5. 批量消息

批量发送消息能显著提高传递小消息的性能。但需要注意这些批量消息应该有相同的topic,相同的waitStoreMsgOK,而且不能是延时消息。此外消息的大小也有限制~

  1. 消息体大小最大为 4MB, 一般建议发送的消息体在 4kb 之内 ( 性能最佳 )。

  2. 消息属性最大为 32kb,一般建议发送的消息属性在 1kb 之内 ( 性能最佳 )。

4MB 这个上限值不能修改,这个会影响全局性能。如果消息体的确很大,建 议侧优化消息体的内容,避免发送大消息或者带有链接地址的消息,或者可 以缩短或者分两条发送。

public <T extends Message> SendResult syncSend(String destination, Collection<T> messages) {
    return syncSend(destination, messages, producer.getSendMsgTimeout());
}

Demo

/**
 * 批量消息
 */
@Test
public void sendOneMsg() {
    ArrayList<Message<String>> messages = new ArrayList<>();
    for (int i = 0; i < 10; i++) {
        messages.add(MessageBuilder.withPayload("批量消息"+(i+1)).build());
    }
    rocketMQTemplate.syncSend("Demo:batch", messages);
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5RtQO05S-1677067621975)(RocketMQTemplate 实现消息发送.assets/image-20230216192416856.png)]

瞅瞅源码

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hsgBtIaO-1677067621976)(RocketMQTemplate 实现消息发送.assets/image-20230216193339428.png)]

6. 异步消息

异步消息无返回值,需要传入回调类。无需等待消息是否发送成功。

public void asyncSend(String destination, Object payload, SendCallback sendCallback) {
    asyncSend(destination, payload, sendCallback, producer.getSendMsgTimeout());
}

Demo

@Test
public void sendAsyncMsg() throws InterruptedException {
    rocketMQTemplate.asyncSend("Demo:async", "异步消息测试", new SendCallback() {
        @Override
        public void onSuccess(SendResult sendResult) {
            System.out.println("异步消息发送成功");
        }

        @Override
        public void onException(Throwable throwable) {
            System.out.println("异步消息发送失败");
        }
    });
    Thread.sleep(1000);
}

源码

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lTUCRsaV-1677067655423)(RocketMQTemplate 实现消息发送.assets/image-20230215205325283.png)]

同理,最终调用的也是producer的send方法。

7. 单向消息

单向消息,与UDP类似,此方法在返回前不会等待代理的确认。显然,它具有最大的吞吐量,但也有消息丢失的可能性。

/**
 * 单向消息,与UDP类似,此方法在返回前不会等待代理的确认。显然,它具有最大的吞吐量,但也有消息丢失的可能性。
 */
@Test
public void sendOneMsg() {
    rocketMQTemplate.sendOneWay("Demo:one", "单向消息测试");
}

源码

/**
 * Same to {@link #sendOneWay(String, Message)}
 *
 * @param destination formats: `topicName:tags`
 * @param payload the Object to use as payload
 */
public void sendOneWay(String destination, Object payload) {
    Message<?> message = MessageBuilder.withPayload(payload).build();
    sendOneWay(destination, message);
}

在这里插入图片描述

8. 顺序消息

大家有没有发现上面批量发送的消息被消费的时候顺序错乱了,有时只有保证消息的顺序消费才有意义。比如网购下单到付款时分别会发送生成订单、锁定库存、成功下单三个消息,消费时要按照这个顺序依次消费才有意义。

顺序错乱的原因

首先,我们先来分析一下顺序错乱的原因,其实RocketMQ里的分区队列MessageQueue本身是能保证FIFO的,正常情况下不能顺序消费消息主要有两个原因:

  1. Producer发送消息到MessageQueue时是轮询发送的,消息被发送到不同的分区队列,就不能保证FIFO了。
  2. Consumer默认是多线程并发消费同一个MessageQueue的,即使消息是顺序到达的,也不能保证消息顺序消费。

综上所述,RocketMQ要想实现顺序消息,核心就是Producer同步发送,确保一组顺序消息被发送到同一个分区队列,然后Consumer确保同一个队列只被一个线程消费。

RocketMQ的特性

顺序消息是RocketMQ的特性之一,它可以让Consumer消费消息的顺序严格按照消息的发送顺序来进行。顺序消息可以分为全局有序和分区有序,绝大部分场景下,分区有序就已经能够满足需求了。

  • 全局有序:某个Topic下所有的消息都是有序的,所有消息按照严格的先进先出的顺序进行生产和消费,要求Topic下只能有一个分区队列,且Consumer只能有一个线程消费,适用对性能要求不高的场景。
  • 分区有序:某个Topic下,所有消息根据ShardingKey进行分区,相同ShardingKey的消息必须被发送到同一个分区队列,因为队列本身是可以保证先进先出的,此时只要保证Consumer同一个队列单线程消费即可。

RocketMQTemplate提供三种发送顺序消息的方式:

  • syncSendOrderly():同步发送顺序消息
  • asyncSendOrderly():异步发送顺序消息
  • sendOneWayOrderly():单向发送顺序消息

源码解析

先了解一下相关的组建类

1、MessageQueueSelector

分区队列选择器,它是一个接口,只有一个select方法,根据ShardingKey从Topic下所有的分区队列中,选择一个目标队列进行消息发送,必须确保相同ShardingKey选择的是同一个分区队列,常见作法是对队列数取模。默认选择队列方式是计算 hashKey 的 hashCode值来选择队列。
在这里插入图片描述

Demo

首先消费者指定最大线程数为一,这样才能确保每个队列只能被一个线程消费
在这里插入图片描述
当我们在发消息时可以通过指定相同的ShardingKey达到多条消息按照发送顺序发送到相同的队列。

/**
 * 顺序消息
 */
@Test
public void sendOrderMsg() {
    for (int i = 0; i < 10; i++) {
        rocketMQTemplate.syncSendOrderly("Demo:order", "同步发送顺序消息"+i, 0+"");
    }

    for (int i = 0; i < 10; i++) {
        rocketMQTemplate.asyncSendOrderly("Demo:order", "异步发送顺序消息" + i, 0 + "", new SendCallback() {
            @Override
            public void onSuccess(SendResult sendResult) {
                return;
            }

            @Override
            public void onException(Throwable e) {
                return;
            }
        });
    }

    for (int i = 0; i < 10; i++) {
        rocketMQTemplate.sendOneWayOrderly("Demo:order", "单向发送顺序消息" + i, 0 + "");
    }

}

或者我们也可以重写MessageQueueSelector类的select()方法自定义选择队列的规则

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xpqu6m5R-1677067748312)(RocketMQTemplate 实现消息发送.assets/image-20230217101616074.png)]

9. 事务消息

分布式消息选型的时候是否支持事务消息是一个很重要的考量点,而目前只有RocketMQ对事务消息支持的最好。

Apache RocketMQ在4.3.0版中已经支持分布式事务消息,这里RocketMQ采用了2PC的思想来实现了提交事务消息,同时增加一个补偿逻辑来处理二阶段超时或者失败的消息,如下图所示。
在这里插入图片描述

概要

RocketMQ实现事务消息主要分为两个阶段:正常事务的发送及提交、事务信息的补偿流程 整体流程为:

  1. 正常事务发送与提交阶段

    1. 生产者发送一个半消息给MQServer(半消息是指消费者暂时不能消费的消息)
    2. 服务端响应消息写入结果,半消息发送成功
    3. 开始执行本地事务
    4. 根据本地事务的执行状态执行Commit或者Rollback操作
  2. 事务信息的补偿流程(补偿阶段主要是用于解决生产者在发送Commit或者Rollback操作时发生超时或失败的情况。)

    1. 如果MQServer长时间没收到本地事务的执行状态会向生产者发起一个确认回查的操作请求
    2. 生产者收到确认回查请求后,检查本地事务的执行状态
    3. 根据检查后的结果执行Commit或者Rollback操作

RocketMQ是如何实现事务消息提交前消费者不可见呢?

事务消息相对普通消息最大的特点就是一阶段发送的消息对用户是不可见的,也就是说消费者不能直接消费。这里RocketMQ的实现方法是原消息的主题与消息消费队列,然后把主题改成RMQ_SYS_TRANS_HALF_TOPIC ,这样由于消费者没有订阅这个主题,所以不会被消费。

如何处理第二阶段的失败消息?

在本地事务执行完成后会向MQServer发送Commit或Rollback操作,此时如果在发送消息的时候生产者出故障了,那么要保证这条消息最终被消费,MQServer会像服务端发送回查请求,确认本地事务的执行状态。
当然了rocketmq并不会无休止的的信息事务状态回查,默认回查15次,如果15次回查还是无法得知事务状态,RocketMQ默认回滚该消息。

事务消息状态有哪几种?

TransactionStatus.CommitTransaction:提交事务消息,消费者可以消费此消息

TransactionStatus.RollbackTransaction:回滚事务,它代表该消息将被删除,不允许被消费。

TransactionStatus.Unknown :未知状态,它代表需要检查消息队列来确定状态。

Demo

首先编写一个Controller模拟发送10调事务消息,并且依次指定key为1~10。

/**
 * 发送事务消息测试
 */
@GetMapping("/tx")
public void sendTransactionMsg() {
    for (int i = 1; i <= 10; i++) {
        // 发送指定事务id的消息
        Message msg = MessageBuilder.withPayload("事务消息" + i).setHeader(RocketMQHeaders.KEYS, i).build();
        TransactionSendResult result = rocketMQTemplate.sendMessageInTransaction("Demo:tx", msg, null);
    }
}

其次,编写一个事务监听器类实现RocketMQLocalTransactionListener的 “执行本地事务” 方法 和 “检查事务状态” 方法。当执行完本地事务方法后,消息的状态为UNKNOWN则会在指定次数下调用 “检查事务状态” 方法。

@Slf4j
@Component
@RequiredArgsConstructor
@RocketMQTransactionListener
public class TransactionListenerImpl implements RocketMQLocalTransactionListener {

    /**
     * 执行本地事务逻辑
     *
     * @param msg
     * @param arg
     * @return
     */
    @Override
    public RocketMQLocalTransactionState executeLocalTransaction(Message msg, Object arg) {
        // 模拟当key为偶数时提交事务,为基数UNKNOWN(在指定次数下检查当前事务状态)
        MessageHeaders headers = msg.getHeaders();
        //获取事务ID
        String transactionId = (String) headers.get(RocketMQHeaders.PREFIX + RocketMQHeaders.TRANSACTION_ID);
        String key = (String) headers.get(RocketMQHeaders.PREFIX + RocketMQHeaders.KEYS);
        log.info("执行本地事务,事务id:{},key:{}", transactionId, key);
        if (Integer.parseInt(key) % 2 == 0) {
            //执行成功,可以提交事务
            return RocketMQLocalTransactionState.COMMIT;
        } else {
            return RocketMQLocalTransactionState.UNKNOWN;
        }
    }

    /**
     * 检查事务状态
     *
     * @param msg
     * @return
     */
    @Override
    public RocketMQLocalTransactionState checkLocalTransaction(Message msg) {
        // 模拟检查事务状态时回滚
        MessageHeaders headers = msg.getHeaders();
        String transactionId = (String) headers.get(RocketMQHeaders.PREFIX + RocketMQHeaders.TRANSACTION_ID);
        String key = (String) headers.get(RocketMQHeaders.PREFIX + RocketMQHeaders.KEYS);
        log.info("检查本地事务,事务id:{},key:{}", transactionId, key);
        return RocketMQLocalTransactionState.ROLLBACK;
    }
}

当我们调用发送事务消息接口时,发现每条消息都会执行本地事务。可以根据消费消息状况分析出事务消息根据我们所设定的key是偶数的情况下发送消息。
在这里插入图片描述
那么对于执行完本地事务后,消息状态为 UNKNOWN(未知)的消息则会在指定次数以及指定时间间隔下检查事务状态。
在这里插入图片描述

源码解读

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
通过源码分析可知,首先是向MqServe发送了事务消息并返回消息的状态。

  • 若消息发送成功为其生成事务id,并执行本地事务方法并返回事务消息状态。
  • 若消息发送失败则默认事务消息状态为回滚。

发送单向消息返回事务状态,MqServe根据消息的事务状态执行相关的事务操作。

  • 如果是 commit 会将消息投递到真实的 topic 中,然后再投递一个表示删除的消息到 RMS_SYS_TRANS_HALF_TOPIC 中,表示当前事务完成;
  • 如果是 rollback,则只需投递表示删除的消息即可
  • 如果是 TRANSACTION_NOT_TYPE,则一段时间后再次及检查,当检查的次数超过上限(默认15次),则丢弃消息

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/364269.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

《羊驼亡命跑》 NFT 系列:羊驼跑酷套装来袭!

完美的羊驼跑酷&#xff01;这一系列植物、平台、愤怒的农民和神秘物品与你们的 Alpacadabraz 化身都是绝配。 关于 Paca Death Run Alpacadabraz 团队推出的首个主要体验的一切都很吸引&#xff01;这款跑酷游戏垂直填满了一个整个 1x1 The Sandbox LAND&#xff0c;挑战玩家在…

扬帆优配|看多A股!多家外资高调发声

外资看多我国的声响和动作正在增多&#xff01; A股商场迎来全面注册制落地后的首个交易日&#xff0c;三大指数集体走强。业内人士分析称&#xff0c;跟着全面实行股票发行注册制改革正式发动&#xff0c;能够预见&#xff0c;跟着商场化程度逐步进步&#xff0c;外资布局我国…

每天五分钟机器学习:新的大规模的机器学习机制——在线学习机制

本文重点 本节课程我们将学习一种新的大规模的机器学习机制--在线学习机制。在线学习机制让我们可以模型化问题。在线学习算法指的是对数据流进行学习而非离线的静态数据集的学习。许多在线网站都有持续不断的用户流,对于每一个用户,网站希望能在不将数据存储到数据库中便顺…

【Mybatis源码分析】datasource配置${}表达式时是如何被解析的?

核心配置中${}表达式配置的解析一、核心配置主体二、核心配置文件中properties是如何被解析的&#xff1f;三、${} 表达式的解析四、总结前提&#xff1a; 核心配置文件是被XMLConfigBuilder 对象进行解析的&#xff0c;configuration 对象是由它父类BaseBuider继承下来的属性…

LQB10,AT24C02的使用

1、单片机用P20和P21和AT24C02通信&#xff1b; 2、比赛提供的开发包里面的代码。 头文件 c文件 提供的代码解读以及修改合适自己使用。 #ifndef _IIC_H #define _IIC_Hvoid IIC_Start(void); void IIC_Stop(void); bit IIC_WaitAck(void); void IIC_SendAck(bit …

产品经理考个 PMP 有用吗?

产品经理考PMP肯定是有用的。学无止境&#xff01; 这里给一些想要转行项目管理的朋友一些PMP考证资料分享&#xff0c;内含不少考纲知识&#xff0c;题库&#xff0c;解题技巧&#xff0c;思维导图等等&#xff0c;有需要就保存下来&#xff0c;留着下次需要的时候用。 一&a…

二、并发编程的三大特性

文章目录并发编程的三大特性1、原子性什么是并发编程的原子性&#xff1f;保证并发编程的原子性synchronizedCASLock锁ThreadLocal2、可见性什么是可见性?解决可见性的方式volatilesynchronizedLockfinal3、有序性什么是有序性?as-if-serialhappens-beforevolatile并发编程的…

谷歌seo新站如何快速排名?如何提高Google自然排名

本文主要分享谷歌SEO如何做新站排名&#xff0c;很多刚出海的外贸小伙伴不会做谷歌SEO&#xff0c;快来学习。 本文由光算创作&#xff0c;有可能会被剽窃和修改&#xff0c;我们佛系对待这种行为吧。 谷歌seo新站如何快速排名&#xff1f; 答案是&#xff1a;大量优质原创内…

科技新浪推前浪 ChatGPT将元宇宙“拍在沙滩上”?

近期ChatGPT的热度显然已经盖过了元宇宙&#xff0c;回想去年元宇宙大热之际&#xff0c;很多企业纷纷跟进&#xff0c;甚至还有不少公司选择更名以表达All In元宇宙的决心。而如今ChatGPT抢占风头&#xff0c;成为新宠&#xff0c;元宇宙似乎被“抛弃”了&#xff0c;难道元宇…

VCL界面组件DevExpress VCL v22.2 - 拥有全新的矢量图形

DevExpress VCL是Devexpress公司旗下最老牌的用户界面套包&#xff0c;所包含的控件有&#xff1a;数据录入、图表、数据分析、导航、布局等。该控件能帮助您创建优异的用户体验&#xff0c;提供高影响力的业务解决方案&#xff0c;并利用您现有的VCL技能为未来构建下一代应用程…

python网络编程详解

最近在看《UNIX网络编程 卷1》和《FREEBSD操作系统设计与实现》这两本书&#xff0c;我重点关注了TCP协议相关的内容&#xff0c;结合自己后台开发的经验&#xff0c;写下这篇文章&#xff0c;一方面是为了帮助有需要的人&#xff0c;更重要的是方便自己整理思路&#xff0c;加…

ElasticSearch Script 操作数据最详细介绍

文章目录ElasticSearch Script基础介绍基础用法List类型数据新增、删除nested数据新增、删除根据指定条件修改数据根据指定条件修改多个字段数据-查询条件也使用脚本根据指定条件删除nested中子数据数据根据条件删除数据删除之后结果创建脚本&#xff0c;通过脚本调用根据条件查…

.net7窗口编程c#2022实战(1)-zip压缩精灵(1)

目录 创建ZIP精灵项目拖控件OpenFileDialog 类压缩与解压缩编写我们自己的代码其它参考内容创建ZIP精灵项目 VS2022中新建项目。 为窗体取一个标题名称 拖控件 左边工具栏里选择控件 拖三个按钮控件和一个listbox控件

动态规划问题汇总(一)

基本步骤 文章目录基本步骤509. 斐波那契数70. 爬楼梯746. 使用最小花费爬楼梯62.不同路径63. 不同路径 II343. 整数拆分96.不同的二叉搜索树509. 斐波那契数 递归版本 class Solution {public int fib(int n) {if(n0){return 0;}if(n1){return 1;}return fib(n-1)fib(n-2);} …

【华为OD机试模拟题】用 C++ 实现 - 求字符串中所有整数的最小和

最近更新的博客 华为OD机试 - 入栈出栈(C++) | 附带编码思路 【2023】 华为OD机试 - 箱子之形摆放(C++) | 附带编码思路 【2023】 华为OD机试 - 简易内存池 2(C++) | 附带编码思路 【2023】 华为OD机试 - 第 N 个排列(C++) | 附带编码思路 【2023】 华为OD机试 - 考古…

2023年2月22日 [随记] 理想、面包

一些简单的吐槽&#xff0c;可以当个故事看一下。 文章目录简单的经历书籍清单这些是买了看过的买了没有仔细看的眨眼间也从业2年11个月多一点&#xff08;就当是三年了&#xff09;&#xff0c;在2023年1月初&#xff0c;距离过年还有两周的时间&#xff0c;因为一些个人原因裸…

拓扑排序的思想?用代码怎么实现

目录 一、拓扑排序的思想 二、代码实现&#xff08;C&#xff09; 代码思想 核心代码 完整代码 一、拓扑排序的思想 以西红柿炒鸡蛋这道菜为例&#xff0c;其中的做饭流程为&#xff1a; 中间2 6 3 7 4的顺序都可以任意调换&#xff0c;但1和5必须在最前面&#xff0c;这是…

详细介绍React生命周期和diffing算法

事件处理 1.通过onXxx属性指定事件处理函数(注意大小写) React使用的是自定义(合成)事件, 而不是使用的原生DOM事件 —— 为了更好的兼容性&#xff1b;React中的事件是通过事件委托方式处理的(委托给组件最外层的元素) ——为了的高效。 2.通过event.target得到发生事件的DOM…

数据挖掘,计算机网络、操作系统刷题笔记54

数据挖掘&#xff0c;计算机网络、操作系统刷题笔记54 2022找工作是学历、能力和运气的超强结合体&#xff0c;遇到寒冬&#xff0c;大厂不招人&#xff0c;可能很多算法学生都得去找开发&#xff0c;测开 测开的话&#xff0c;你就得学数据库&#xff0c;sql&#xff0c;orac…

搭建kafka集群

Kafka集群依赖ZK&#xff0c;需要先启动ZK集群 机器&#xff1a;hadop101,hadoop102, hadoop103 【1】在hadoop101解压&#xff1a; tar -zxvf kafka_2.12-2.4.1.tgz -C ../module/ 【2】在hadoop101修改server.properties配置&#xff1a; #指定broker的id&#xff0c;类似zk…