第03讲:SpringCloudStream实现分布式事务

news2025/1/19 23:19:37

在这里插入图片描述

需求分析

本案例是通过一个发送短信验证码的功能来实验MQ发送消息时实现分布式事务,思路分析如下

  • 消息生产者生产发送验证码的半消息

  • 生产者执行本地事务(将验证码保存到数据库),并记录事务的ID,如果整个过程不出现异常,则提交事务,消息成功投递,否则进行事务的回滚操作

  • MQ二次确认消息是否成功投递,如果没成功(发生了异常),则丢弃消息

需求实现

一、创建项目

  • 创建一个主工程(stream-mq-demo),目的是维护项目的版本号、一些必要的类库、集成SpringCloudAlibaba
  • 子工程(producer),目的是生产发送验证码的消息,及使用事务将验证码保存到数据库
  • 子工程(consumer),目的是消费消息

二、主工程

2.1、pom.xml

目的是维护项目的版本号、一些必要的类库、以及集成SpringCloudAlibaba

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.5.RELEASE</version>
    </parent>

    <groupId>org.example</groupId>
    <artifactId>stream-mq-demo</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>producer</module>
        <module>consumer</module>
    </modules>

    <properties>
        <spring-cloud.version>Greenwich.SR1</spring-cloud.version>
        <spring-cloud-alibaba.version>0.9.0.RELEASE</spring-cloud-alibaba.version>
        <java.version>1.8</java.version>
        <lombok.version>1.18.8</lombok.version>
        <rocketmq.version>2.0.3</rocketmq.version>
        <mybatis.plus.version>3.5.1</mybatis.plus.version>
        <mysql.version>8.0.32</mysql.version>
    </properties>

    <dependencies>
        <!-- RocketMQ坐标 -->
        <dependency>
            <groupId>org.apache.rocketmq</groupId>
            <artifactId>rocketmq-spring-boot-starter</artifactId>
            <version>${rocketmq.version}</version>
        </dependency>
        <!-- SpringCloudStream坐标 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-stream-rocketmq</artifactId>
        </dependency>
        <!-- SpringWeb坐标 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- lombok坐标 -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>${lombok.version}</version>
        </dependency>
        <!-- test -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <!--整合spring cloud-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!--整合spring cloud alibaba-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${spring-cloud-alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
</project>

三、Producer子工程

3.1、pom.xml

添加MyBatisPlus、MySQL、FastJSON类库

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>stream-mq-demo</artifactId>
        <groupId>org.example</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>producer</artifactId>

    <dependencies>
        <!-- mybatis-plus -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>${mybatis.plus.version}</version>
        </dependency>
        <!-- mysql-connector -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql.version}</version>
        </dependency>
        <!-- fastjson -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>2.0.12</version>
        </dependency>
    </dependencies>
</project>

3.2、application.yml

  • 配置数据源(application_druid.yml)
  • 配置端口号为8081
  • 配置MQ的name-server地址
  • 配置SpringCloudStream的消费者模式并开启事务
  • 配置MQ的topic

数据源application_druid.yml

spring:
  datasource:
    type: com.zaxxer.hikari.HikariDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://192.168.0.3:3306/mq_demo?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true
    username: root
    password: Aa123123.
  jackson:
    date-format: yyyy-MM-dd HH:mm:ss
mybatis-plus:
  type-aliases-package: demo.entity
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  global-config:
    db-config:
      table-prefix: t_

主配置文件application.yml

spring:
  profiles:
    include: druid
  cloud:
    stream:
      rocketmq:
        binder:
          name-server: 192.168.0.3:9876
        bindings:
          #消费者
          output:
            producer:
              #事务消息
              transactional: true
              #与AddBonusTransactionListener类中@RocketMQTransactionListener一致
              group: tx-captcha-group
      bindings:
        output:
          #用来指定topic,要和content-center微服务的topic匹配
          destination: captcha-topic
server:
  port: 8081

3.3、启动类

使用@EnableBinding(Source.class)定义消息的推送管道

Source.class源代码

public interface Source {
    String OUTPUT = "output";

    @Output("output")
    MessageChannel output();
}

application.yml中配置的output属性

在这里插入图片描述

启动类

package demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.messaging.Source;

@SpringBootApplication
@EnableBinding(Source.class)
public class ProducerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ProducerApplication.class, args);
    }
}

3.4、必要的实体类

验证码类

package demo.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import lombok.Builder;
import lombok.Data;

import java.util.Date;

@Data
@Builder
public class Captcha {
    @JsonSerialize(using = ToStringSerializer.class)
    @TableId(type = IdType.AUTO)
    private Integer id;
    private String captcha;
    private String phone;
    private Date publishTime;
}

事务日志类

package demo.entity;

import lombok.Builder;
import lombok.Data;

import java.util.Date;

@Data
@Builder
public class TransactionLog {
    private String transactionId;
    private Date createTime;
    private String log;
}

3.5、本地事务类

  • 发送半消息
  • 保存验证码到数据库并记录日志
package demo.service;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import demo.entity.Captcha;
import demo.entity.TransactionLog;
import demo.mapper.CaptchaMapper;
import demo.mapper.TransactionLogMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.spring.support.RocketMQHeaders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.stream.messaging.Source;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

@Slf4j
@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class SendCaptchaService {

    private final Source source;
    private final TransactionLogMapper transactionLogMapper;
    private final CaptchaMapper boundMapper;

    /** 发送半消息*/
    public void sendCaptchaMsg(Captcha captcha){
        // 发送半消息。。
        String transactionId = UUID.randomUUID().toString();

        Map<String, Object> msg = new HashMap<>();
        msg.put("phone", captcha.getPhone());
        msg.put("captcha", captcha.getCaptcha());

        this.source.output()
                .send(
                        MessageBuilder
                                .withPayload(msg)
                                // header也有妙用...
                                .setHeader(RocketMQHeaders.TRANSACTION_ID, transactionId)
                                .setHeader("dto", JSON.toJSONString(captcha))
                                .build()
                );
    }

    /**添加验证码到数据库,并记录事务日志*/
    @Transactional(rollbackFor = Exception.class)
    public void addBoundWithRocketMqLog(Captcha captcha, String transactionId) {
        //执行本地事务
       this.addBound(captcha);

        //记录MQ事务日志
        transactionLogMapper.insert(
                TransactionLog.builder()
                        .transactionId(transactionId)
                        .createTime(new Date())
                        .log("发送短信验证码")
                        .build()
        );
    }

    /**将验证码保存到数据库*/
    @Transactional(rollbackFor = Exception.class)
    public void addBound(Captcha captcha){
        captcha.setPublishTime(new Date());
        boundMapper.insert(captcha);
    }
}

3.6、MQ事务类

MQ事务类实现RocketMQLocalTransactionListener接口

  • 重写用于执行本地事务的方法executeLocalTransaction,在该方法中执行本地事务类的保存验证码到数据库并记录日志的方法addBoundWithRocketMqLog
  • 重写本地事务的检查接口,检查本地事务是否执行成功,即:MQ没有收到执行本地事务后的二次确认checkLocalTransaction,在该方法中去查询事务日志表(t_transaction_log)是否存在相同事务ID的日志,如果不存在则将消息丢弃,否则标记为成功投递
package demo.mq;

import com.alibaba.fastjson.JSON;
import demo.entity.Captcha;
import demo.entity.TransactionLog;
import demo.mapper.TransactionLogMapper;
import demo.service.SendCaptchaService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.spring.annotation.RocketMQTransactionListener;
import org.apache.rocketmq.spring.core.RocketMQLocalTransactionListener;
import org.apache.rocketmq.spring.core.RocketMQLocalTransactionState;
import org.apache.rocketmq.spring.support.RocketMQHeaders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHeaders;

@RocketMQTransactionListener(txProducerGroup = "tx-captcha-group")
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
@Slf4j
public class SendCaptchaTransactionListener implements RocketMQLocalTransactionListener {

    private final SendCaptchaService addBoundService;
    private final TransactionLogMapper transactionLogMapper;

    /** 用于执行本地事务的方法*/
    @Override
    public RocketMQLocalTransactionState executeLocalTransaction(Message msg, Object arg) {
        MessageHeaders headers = msg.getHeaders();

        String transactionId = (String) headers.get(RocketMQHeaders.TRANSACTION_ID);

        String dtoString = (String) headers.get("dto");
        Captcha bound = JSON.parseObject(dtoString, Captcha.class);

        //本地事务(service层用@Transaction标注的方法)成功就提交,本地事务失败就回滚
        try {
            //执行本地事务
            addBoundService.addBoundWithRocketMqLog(bound, transactionId);
            return RocketMQLocalTransactionState.COMMIT; //本地事务执行成功就提交MQ
        } catch (Exception e) {
            return RocketMQLocalTransactionState.ROLLBACK; //本地事务执行失败就回滚MQ
        }
    }

    /** 本地事务的检查接口,检查本地事务是否执行成功,即:MQ没有收到执行本地事务后的二次确认*/
    @Override
    public RocketMQLocalTransactionState checkLocalTransaction(Message msg) {
        MessageHeaders headers = msg.getHeaders();
        String transactionId = (String) headers.get(RocketMQHeaders.TRANSACTION_ID);
        log.info("MQ二次事务检查,transactionID={}", transactionId);

        // 从MQ事务日志表里查,看看对应的事务ID是否存在记录,如果存在则表示成功(COMMIT),否则表示执行本地事务失败(ROLLBACK)
        TransactionLog transactionLog = transactionLogMapper.selectById(transactionId);

        if (transactionLog != null) {
            return RocketMQLocalTransactionState.COMMIT;
        } else {
            return RocketMQLocalTransactionState.ROLLBACK;
        }
    }
}

3.7、测试

使用单元测试,创建测试方法调用本地事务类发送半消息

package demo;

import demo.entity.Captcha;
import demo.service.SendCaptchaService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@SpringBootTest(classes = {ProducerApplication.class})
@RunWith(SpringJUnit4ClassRunner.class)
public class TestSendCaptcha {

    @Autowired
    private SendCaptchaService sendCaptchaMsg;

    @Test
    public void test(){
        //随机生成一个4位的验证码
        String code = "";
        for(int i=0; i<4; i++){
            code += (int)(Math.random()*10);
        }
        //发送半消息
        sendCaptchaMsg.sendCaptchaMsg(
                Captcha.builder()
                        .captcha(code)
                        .phone("13843188848")
                        .build()
        );
    }
}

运行单元测试方法之后浏览器访问MQ-Dashboard可以看到topic已经被创建

在这里插入图片描述

在Message中可以看到刚刚发送的消息

在这里插入图片描述

消息详情

在这里插入图片描述

数据库验证码表(t_captcha)插入了数据

数据库事务日志表(t_transaction_log)插入了数据

在这里插入图片描述

Tip:可以在本地事务中模拟一个运行时异常,可以发现事务日志表中并无法插入日志,在MQ事务二次确认消息的时候会讲消息丢弃

四、Consumer子工程

4.1、application.yml

  • 配置端口号为8082
  • 配置MQ的name-server地址
  • 配置MQ的topic
  • 配置group,如果使用的消息队列是RocketMQ,则该属性务必配置,内容可以是任意字符串
spring:
  cloud:
    stream:
      rocketmq:
        binder:
          name-server: 192.168.0.3:9876
      bindings:
        #消息消费者
        input:
          #用来指定topic,要和消息生产者的的topic匹配
          destination: captcha-topic
          #一定要设置,必填项,如果用其他MQ,该属性可以不设置
          group: test
server:
  port: 8082

4.2、启动类

  • 使用@EnableBinding(Sink.class)定义消息的推送管道

Sink.class源代码

public interface Sink {
    String INPUT = "input";

    @Input("input")
    SubscribableChannel input();
}

application.yml中配置的input属性

在这里插入图片描述

  • 使用@StreamListener(Sink.INPUT)注解监听消息
  • 使用@StreamListener(“errorChannel”)统一处理MQ的异常

启动类

package demo;

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.annotation.StreamListener;
import org.springframework.cloud.stream.messaging.Sink;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.ErrorMessage;

import java.util.HashMap;

@Slf4j
@SpringBootApplication
@EnableBinding(Sink.class)
public class ConsumerApplication {

    /**
     * 消费消息监听器
     *
     * @param message
     */
    @StreamListener(Sink.INPUT)
    public void receive(HashMap<String, Object> message) {
        log.info("消费消息={}", message);
    }

    /**
     * 全局异常处理
     *
     * @param message 发生异常的消息
     */
    @StreamListener("errorChannel")
    public void error(Message<?> message) {
        ErrorMessage errorMessage = (ErrorMessage) message;
        log.warn("RocketMQ-SpringCloudStream发生异常,errorMessage={}", errorMessage);
    }

    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class, args);
    }
}

4.3、测试

再次执行Producer子工程单元测试方法发送半消息,发现在Consumer子工程中成功监听到了消息

在这里插入图片描述

4.4、消息过滤器

​ 在@StreamListener注解中可以使用condition属性来定义要匹配(过滤)的消息,将消费者改造一下,只接收手机号为13843188848的消息

Tip:该方式只支持RoketMQ,不支持Kafka/RabbitMQ

		/**
     * 消费消息监听器
     *
     * condition的作用是消息过滤,当前案例是匹配消息中header属性phone的值为13843188848的消息
     */
    @StreamListener(value = Sink.INPUT, condition = "headers['phone']=='13843188848'")
    public void receive(HashMap<String, Object> message) {
        log.info("消费消息={}", message);
    }

如果不满足匹配条件将会有提示

在这里插入图片描述

但是消息已经成功发送

在这里插入图片描述

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

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

相关文章

[点云学习] 一、点云相关知识了解

1.何谓点云&#xff1f; 点云是一种表示三维空间中对象的数据结构&#xff0c;它由许多离散的点组成。每个点都有自己的位置坐标和可能的其他属性&#xff0c;如颜色、法向量和强度等。点云通常由激光扫描仪、相机或其他传感器捕获&#xff0c;用于创建三维模型、地图或进行遥感…

three.js学习 11 - 1.threejs常用几何体 2.几何体材质自定义 3.材质的旋转与堆叠效果

1.threejs常用几何体 ①.缓冲几何体&#xff08;立方体&#xff09; 官网API地址&#xff1a;https://www.three3d.cn/docs/index.html?qgeometry#api/zh/geometries/BoxGeometry ②.圆缓冲几何体 官网地址&#xff1a;https://www.three3d.cn/docs/index.html?qgeometry#a…

内存一致性(Memory Consistency)模型简介

这里写自定义目录标题 1. 前言2 为什么需要内存一致性(Memory Consistency)模型3. 什么是内存一致性(Memory Consistency)模型4. 各种内存一致性(Memory Consistency)模型4.1 顺序一致性(SC: Sequential Consistency)模型4.2 完全存储定序(TSO: Total Store Order)模型4.3 部分…

外贸人如何精准开发客户?Facebook开发客户全攻略

现在做跨境的都了解的一个社媒平台就是Facebook了&#xff0c;因为很多人都会拿Facebook来开发客户&#xff0c;忙里偷闲&#xff0c;今天东哥就来聊聊用Facebook开发客户的一些心得。 用Facebook开发客户的心得 1、利用关键词搜索 使用行业相关的关键词、产品特定的关键词、相…

菁染料-N-羟基琥珀酰亚胺酯Cyanine7-NHS ester活性脂1432019-64-1

CY7-NHS ester是一种荧光染料&#xff0c;具有橙红色荧光。它的化学式为C41H48ClN3O4&#xff0c;分子量为733.64。CY7-NHS的荧光特性适合生物学应用&#xff0c;它的激发波长为750nm&#xff0c;发射波长为773nm&#xff0c;可用于近红外成像。这种标记物可以用于活细胞成像、…

案例10:Java外卖平台设计与实现开题报告

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…

web开发中如何知道表单的数据是否发生了变更,后端框架又是如何响应的,都有哪些方案

前言 针对web界面开发&#xff0c;今天对于一些细节做了一点总结与回想&#xff0c;好久不做web开发了&#xff0c;今天竟然都忘记了以前的界面组件、后端orm映射框架的一些基础知识了&#xff0c;今天主要总结的内容是&#xff0c;当界面提交一个表单后&#xff0c;vue是如何…

【JavaEE】wait/notify方法 和 单例模型

目录 前言 1、 wait和notify 1.1、wait()方法 1.2、notify&#xff08;&#xff09;方法 1.3、wait和sleep 的对比 2、单例模式 2.1、饿汉模式 2.2、懒汉模式 2.3、上述懒汉模式和饿汉模式在多线程情况下是否安全 2.3.1、解决懒汉模式多线程不安去问题 前言 这里补充…

网络安全面试题合集

以下为网络安全各个方向涉及的面试题&#xff0c;星数越多代表问题出现的几率越大&#xff0c;祝各位都能找到满意的工作。 注&#xff1a;本套面试题&#xff0c;已整理成pdf文档&#xff0c;但内容还在持续更新中&#xff0c;因为无论如何都不可能覆盖所有的面试问题&#xf…

瑞吉外卖 - 启用与禁用员工账号功能(8)

某马瑞吉外卖单体架构项目完整开发文档&#xff0c;基于 Spring Boot 2.7.11 JDK 11。预计 5 月 20 日前更新完成&#xff0c;有需要的胖友记得一键三连&#xff0c;关注主页 “瑞吉外卖” 专栏获取最新文章。 相关资料&#xff1a;https://pan.baidu.com/s/1rO1Vytcp67mcw-PD…

最新入河排污口设置论证、水质影响预测与模拟、污水处理工艺分析及典型建设项目入河排污口方案报告书

随着水资源开发利用量不断增大&#xff0c;全国废污水排放量与日俱增&#xff0c;部分河段已远远超出水域纳污能力。近年来,部分沿岸入河排污口设置不合理&#xff0c;超标排污、未经同意私设排污口等问题逐步显现&#xff0c;已威胁到供水安全、水环境安全和水生态安全&#x…

Packet Tracer – 配置 VLAN

Packet Tracer – 配置 VLAN 地址分配表 设备 接口 IP 地址 子网掩码 VLAN PC1 NIC 172.17.10.21 255.255.255.0 10 PC2 NIC 172.17.20.22 255.255.255.0 20 PC3 NIC 172.17.30.23 255.255.255.0 30 PC4 NIC 172.17.10.24 255.255.255.0 10 PC5 NI…

open3d 表面重建

目录 1. create_from_point_cloud_ball_pivoting 2. create_from_point_cloud_alpha_shape 3. create_from_point_cloud_poisson 从以下效果来看&#xff0c;第三个方法最好。 1. create_from_point_cloud_ball_pivoting 关键代码&#xff1a; rec_mesh o3d.geometry.T…

面试被问麻了....

前几天组了一个软件测试面试的群&#xff0c;没想到效果直接拉满&#xff0c;看来大家对面试这块的需求还是挺迫切的。昨天我就看到群友们发的一些面经&#xff0c;感觉非常有参考价值&#xff0c;于是我就问他还有没有。 结果他给我整理了一份非常硬核的面筋&#xff0c;打开…

2022年美国大学生数学建模竞赛F题人人为我,我为人人解题全过程文档及程序

2022年美国大学生数学建模竞赛 F题 人人为我&#xff0c;我为人人 原题再现&#xff1a; 背景:   世界上大多数国家签署了1967年联合国《外层空间条约》&#xff0c;条约内容包括同意探索和利用外层空间&#xff0c;包括月球和其他天体&#xff0c;不论各国经济或科学发展程…

低成本挖出电商API接口-程序员要注意那些事项-技术分享

在开发电商应用的过程中&#xff0c;获取天猫API接口是非常必要的一步。天猫API提供了丰富的商品数据获取、订单管理、支付管理等功能&#xff0c;但是天猫API一般需要进行开发者认证&#xff0c;而认证需要企业资质和若干费用支出&#xff0c;这对个人开发者和小型业务开发者来…

Postgresql数组与Oracle嵌套表的使用区别

oracle中的多维数组 Oracle中常说的数组就是嵌套表&#xff0c;下面给出两个多维使用实例&#xff0c;引出和PG的差异&#xff1a; 一维赋值&#xff08;第一行给1列&#xff09; set serveroutput on; declaretype arr_num is table of number;type arr_arr_num is table o…

任务队列的Java实现

一、需求背景 当前项目中遇到这样一个需求: 将需要审核的文本提交给人工智能模型接口审核&#xff0c;等待模型接口审核完毕以后拿到审核结果返回给前端展示给用户&#xff08;另&#xff1a;模型处理数据所消耗的时间会随着用户提交数据的复杂度有所变化&#xff09;。 以上需…

毫米波雷达系列 | 传统CFAR检测(自适应类)

毫米波雷达系列 | 传统CFAR检测&#xff08;自适应类&#xff09; VI-CFAR [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dV34CKJt-1684215839850)(毫米波雷达系列 传统CFAR检测&#xff08;自适应类&#xff09;.assets/image-20230516131206695…

Recognizing Micro-Expression in Video Clip with Adaptive Key-Frame Mining阅读笔记

本文主要贡献 据我们所知&#xff0c;这是第一项旨在将视频剪辑中的信息时间子集的端到端学习与单个网络中的微表情识别相结合的工作。 此外&#xff0c;所提出网络中所有模块的设计都与输入视频剪辑的长度无关。 换句话说&#xff0c;网络容忍各种长度的微表情剪辑。 本文的贡…