RocketMQ笔记(七)SpringBoot整合RocketMQ发送事务消息

news2024/10/7 16:22:39

目录

    • 一、简介
      • 1.1、流程图
      • 1.2、事务消息流程介绍
    • 二、Maven依赖
    • 三、生产者
      • 3.1、application配置
      • 3.2、员工表
      • 3.3、实体
      • 3.4、持久层
      • 3.5、监听器
    • 四、测试
      • 4.1、普通消息
      • 4.2、事务消息
        • 4.2.1、消费者
        • 4.2.2、正常提交
        • 4.2.3、异常提交
    • 五、其他
      • 5.1、接口说明
      • 5.2、checkLocalTransaction不回调

一、简介

  在之前的文章中,我讲过了,同步发送单条消息,异步发送单条消息,发送单向消息,发送顺序消息,以及批量发送消息,延迟消息。今天说下发送事务消息。

1.1、流程图

  事务消息交互流程如下图所示。
在这里插入图片描述

1.2、事务消息流程介绍

  事务消息交互流程如下图所示。

  1. 生产者将消息发送至Apache RocketMQ服务端
  2. Apache RocketMQ服务端将消息持久化成功之后,向生产者返回Ack确认消息已经发送成功,此时消息被标记为"暂不能投递",这种状态下的消息即为半事务消息
  3. 生产者开始执行本地事务逻辑
  4. 生产者根据本地事务执行结果向服务端提交二次确认结果(Commit或是Rollback),服务端收到确认结果后处理逻辑如下:
  • 二次确认结果为Commit:服务端将半事务消息标记为可投递,并投递给消费者
  • 二次确认结果为Rollback:服务端将回滚事务,不会将半事务消息投递给消费者
  1. 在断网或者是生产者应用重启的特殊情况下,若服务端未收到发送者提交的二次确认结果,或服务端收到的二次确认结果为Unknown未知状态,经过固定时间后,服务端将对消息生产者即生产者集群中任一生产者实例发起消息回查。 说明 服务端回查的间隔时间和最大回查次数
  2. 生产者收到消息回查后,需要检查对应消息的本地事务执行的最终结果
  3. 生产者根据检查到的本地事务的最终状态再次提交二次确认,服务端仍按照步骤4对半事务消息进行处理

二、Maven依赖

pom.xml

<?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>rocketmq</artifactId>
        <groupId>com.alian</groupId>
        <version>1.0.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>06-send-transactional-message</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.2.6</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.26</version>
            <scope>runtime</scope>
        </dependency>

        <dependency>
            <groupId>com.alian</groupId>
            <artifactId>common-rocketmq-dto</artifactId>
            <version>1.0.0-SNAPSHOT</version>
        </dependency>

    </dependencies>

</project>

  父工程已经在我上一篇文章里,通用公共包也在我上一篇文章里有说明,包括消费者。具体参考:RocketMQ笔记(一)SpringBoot整合RocketMQ发送同步消息

三、生产者

3.1、application配置

application.properties

server.port=8006

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.type= com.alibaba.druid.pool.DruidDataSource
spring.datasource.username=test
spring.datasource.password=Alian!@34
spring.datasource.url=jdbc:mysql://192.168.0.139:3306/test?characterEncoding=utf8&useUnicode=true&useSSL=false&zeroDateTimeBehavior=convertToNull&autoReconnect=true&allowMultiQueries=true&failOverReadOnly=false&connectTimeout=6000&maxReconnects=5
spring.datasource.initialSize=5
spring.datasource.minIdle= 5
spring.datasource.maxActive=20

# rocketmq地址
rocketmq.name-server=192.168.0.234:9876
# 默认的生产者组
rocketmq.producer.group=transactional_group
# 发送同步消息超时时间
rocketmq.producer.send-message-timeout=3000
# 用于设置在消息发送失败后,生产者是否尝试切换到下一个服务器。设置为 true 表示启用,在发送失败时尝试切换到下一个服务器
rocketmq.producer.retry-next-server=true
# 用于指定消息发送失败时的重试次数
rocketmq.producer.retry-times-when-send-failed=3
# 设置消息压缩的阈值,为0表示禁用消息体的压缩
rocketmq.producer.compress-message-body-threshold=0

  在 RocketMQ 中,RocketMQTemplatesyncSend方法,它允许你批量发送同步消息,主要参数:

  • topic:主题
  • Message:消息内容
  • timeout:发送超时时间
  • delayLevel:延迟级别

3.2、员工表

员工实体

CREATE TABLE `employee` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
  `code` varchar(8) NOT NULL DEFAULT '' COMMENT '编号',
  `emp_name` varchar(20) NOT NULL DEFAULT '' COMMENT '姓名',
  `age` int(2) NOT NULL DEFAULT '0' COMMENT '年龄',
  `salary` double(8,2) NOT NULL DEFAULT '0.00' COMMENT '工资',
  `department` varchar(20) NOT NULL DEFAULT '' COMMENT '部门',
  `hire_date` date NOT NULL DEFAULT '1970-07-01' COMMENT '入职时间',
  PRIMARY KEY (`id`),
  UNIQUE KEY `code_UNIQUE` (`code`),
  KEY `idx_code` (`code`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4

3.3、实体

实体类

@Data
@Entity
public class Employee implements Serializable {

    private static final long serialVersionUID = 1L;

    /**
     * 员工编号
     */
    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    /**
     * 员工编号
     */
    @Column(name = "code")
    private String code;

    /**
     * 员工姓名
     */
    @Column(name = "emp_name")
    private String name;

    /**
     * 员工年龄
     */
    @Column(name = "age")
    private int age;

    /**
     * 工资
     */
    @Column(name = "salary")
    private double salary = 0.00;

    /**
     * 部门
     */
    @Column(name = "department")
    private String department;

    /**
     * 入职时间
     */
    @Column(name = "hire_date")
    private LocalDate hireDate;

}

3.4、持久层

持久层

public interface EmployeeRepository extends PagingAndSortingRepository<Employee, Integer> {

    Employee findByCode(String code);
}

3.5、监听器

  首先我们需要配置自定义的 RocketMQTemplate,最重要的是设置 TransactionMQProducer 的生产者组名称,这里是custom_transactional_group

  配置扩展的 RocketMQTemplate的类,并指定了 RocketMQ 生产者组的名称为custom_transactional_group。这个扩展的 RocketMQTemplate类可以用于发送事务消息以及其他类型的消息。

package com.alian.transactional.listener;

import com.alian.transactional.domain.Employee;
import com.alian.transactional.repository.EmployeeRepository;
import com.alibaba.fastjson.JSON;
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.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.Message;

@Slf4j
@RocketMQTransactionListener(rocketMQTemplateBeanName = "rocketMQTemplate")
public class EmployeeTransactionListener implements RocketMQLocalTransactionListener {

    @Autowired
    private EmployeeRepository employeeRepository;

    @Override
    public RocketMQLocalTransactionState executeLocalTransaction(Message message, Object o) {
        try {
            log.info("事务消息Headers为:{}", message.getHeaders());
            String payload = new String((byte[]) message.getPayload());
            log.info("事务消息为:{}", payload);
            Employee employee = JSON.parseObject(payload, Employee.class);
            employee.setId(null);
            Employee save = employeeRepository.save(employee);
            if (save.getId() != null) {
                log.info("保存员工成功:{}", save.getId());
                return RocketMQLocalTransactionState.COMMIT;
            }
            log.info("保存员工失败:{}", save.getId());
        } catch (Exception e) {
            log.error("发送事务消息异常:{}", e.getMessage());
            return RocketMQLocalTransactionState.UNKNOWN;
        }
        return RocketMQLocalTransactionState.ROLLBACK;

    }

    @Override
    public RocketMQLocalTransactionState checkLocalTransaction(Message message) {
        String id = message.getHeaders().get("rocketmq_KEYS").toString();
        log.info("事务消息key为:{}", id);
        Employee employee = employeeRepository.findByCode(id);
        if (employee == null) {
            return RocketMQLocalTransactionState.ROLLBACK;
        }
        return RocketMQLocalTransactionState.COMMIT;
    }

}

四、测试

4.1、普通消息

  

@Slf4j
@SpringBootTest
public class SendTransactionalMessageTest {

    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    @Test
    public void syncSendStringMessage() {
        String topic = "string_message_topic";
        String message = "我是一条同步文本消息:syncSendStringMessage";
        SendResult sendResult = rocketMQTemplate.syncSend(topic, message);
        log.info("同步发送返回的结果:{}", sendResult);
    }

    @AfterEach
    public void waiting() {
        try {
            Thread.sleep(10000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}

运行结果:

同步发送返回的结果:SendResult [sendStatus=SEND_OK, msgId=7F000001109818B4AAC24B519EC40000, offsetMsgId=C0A800EA00002A9F000000000000371F, messageQueue=MessageQueue [topic=string_message_topic, brokerName=rocketmq, queueId=2], queueOffset=1]

字符串消费者接收到的消息: 我是一条同步文本消息:syncSendStringMessage

此处我们还是能正常发送普通消息。

4.2、事务消息

4.2.1、消费者

  首先我们要在之前的消费者,增加一个消费监听

@Slf4j
@Component
@RocketMQMessageListener(topic = "transaction_message_topic", consumerGroup = "CONCURRENT_GROUP_TRANSACTION")
public class TransactionMessageConsumer implements RocketMQListener<JSONObject> {

    @Override
    public void onMessage(JSONObject json) {
        log.info("接收到事务消息:{}", json);
    }
}
4.2.2、正常提交

  接着,我们先测试正常发送消息(发送半事务消息,本地保存记录,成功提交事务)。

@Slf4j
@SpringBootTest
public class SendTransactionalMessageTest {

    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    @Test
    public void sendMessageInTransaction() {
        // 计算过期时间戳
        String uuid = UUID.randomUUID().toString().replace("-", "");
        String topic = "transaction_message_topic";

        String code = "BAT10015";
        JSONObject json = new JSONObject();
        json.put("code", code);
        json.put("name", "张若尘");
        json.put("age", "25");
        json.put("salary", "15000");
        json.put("department", "测试部");
        json.put("hireDate", "2020-05-21");
        Message<JSONObject> rocketMessage = MessageBuilder.withPayload(json)
                // 根据需要设置
                .setHeader(RocketMQHeaders.TRANSACTION_ID, uuid)
                // 设置一个业务的key,以便事务回查时使用
                .setHeader(RocketMQHeaders.KEYS, code)
                .build();
        // 发送事务消息
        TransactionSendResult transactionSendResult = rocketMQTemplate.sendMessageInTransaction(topic, rocketMessage, null);
        log.info("【发送状态】:{}", transactionSendResult.getLocalTransactionState());
    }

    @AfterEach
    public void waiting() {
        try {
            // 休眠时间3分钟
            Thread.sleep(180000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}

生产者运行结果:

事务消息Headers为:{rocketmq_TOPIC=transaction_message_topic, rocketmq_FLAG=0, __transactionId__=7F000001326018B4AAC24B72107D0000, rocketmq_TRANSACTION_ID=7F000001326018B4AAC24B72107D0000, rocketmq_KEYS=BAT10015, id=c98dca25-50b7-9c9a-fc5f-b7ab7bea18eb, TRANSACTION_ID=0055a562d5af4db0a19f2939124a82f0, contentType=application/json, timestamp=1710488166582}
事务消息为:{"hireDate":"2020-05-21","code":"BAT10015","name":"张若尘","salary":"15000","department":"测试部","age":"25"}
保存员工成功:25
【发送状态】:COMMIT_MESSAGE

消费者运行结果:

接收到事务消息:{"hireDate":"2020-05-21","code":"BAT10015","name":"张若尘","salary":"15000","department":"测试部","age":"25"}

  从上面的监听器保存成功记录后,返回了 RocketMQLocalTransactionState.COMMIT,所以我们的事务是正常提交的,半事务消息也被推送到消息者队列了。

4.2.3、异常提交

  因为,我们数据库表设计时,code字段的长度是8位,我们就插入一个大于8位的值,然后抛出一个异常,然后rocketmq 会进行回查

@Slf4j
@SpringBootTest
public class SendTransactionalMessageTest {

    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    @Test
    public void sendMessageInTransaction() {
        // 计算过期时间戳
        String uuid = UUID.randomUUID().toString().replace("-", "");
        String topic = "transaction_message_topic";

        String code = "BAT8888888";
        JSONObject json = new JSONObject();
        json.put("code", code);
        json.put("name", "张若尘");
        json.put("age", "25");
        json.put("salary", "15000");
        json.put("department", "测试部");
        json.put("hireDate", "2020-05-21");
        Message<JSONObject> rocketMessage = MessageBuilder.withPayload(json)
                // 根据需要设置
                .setHeader(RocketMQHeaders.TRANSACTION_ID, uuid)
                // 设置一个业务的key,以便事务回查时使用
                .setHeader(RocketMQHeaders.KEYS, code)
                .build();
        // 发送事务消息
        TransactionSendResult transactionSendResult = rocketMQTemplate.sendMessageInTransaction(topic, rocketMessage, null);
        log.info("【发送状态】:{}", transactionSendResult.getLocalTransactionState());
    }

    @AfterEach
    public void waiting() {
        try {
            // 休眠时间3分钟
            Thread.sleep(180000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}

运行结果:

事务消息Headers为:{rocketmq_TOPIC=transaction_message_topic, rocketmq_FLAG=0, __transactionId__=7F00000107B018B4AAC24B6E46F00000, rocketmq_TRANSACTION_ID=7F00000107B018B4AAC24B6E46F00000, rocketmq_KEYS=BAT888888, id=9d148765-9f66-2242-af17-0591c8378c7a, TRANSACTION_ID=26930ad65e7c40738aa24c6cb5c3da61, contentType=application/json, timestamp=1710487918377}
事务消息为:{"hireDate":"2020-05-25","code":"BAT888888","name":"Alian","salary":"35000","department":"研发部","age":"28"}
SQL Error: 1406, SQLState: 22001
Data truncation: Data too long for column 'code' at row 1
发送事务消息异常:could not execute statement; SQL [n/a]; nested exception is org.hibernate.exception.DataException: could not execute statement
【发送状态】:UNKNOW

事务消息key为:BAT888888
本地事务失败,删除消息:BAT888888

  从上面的监听器保存异常(Data too long for column ‘code’),返回了 RocketMQLocalTransactionState.UNKNOWN(只是模拟返回),就不知道本地事务到底是成功还是失败,所以需要进行事务回查,也就是要调用:checkLocalTransaction放,检查本地是否正常,因为不存在记录,我们返回RocketMQLocalTransactionState.ROLLBACK,半事务消息就被删除了。

五、其他

5.1、接口说明

  在springBoot整合中,实现的接口是RocketMQLocalTransactionListener接口,而不是TransactionListener。其中executeLocalTransaction 是半事务消息发送成功后,执行本地事务的方法,具体执行完本地事务后,可以在该方法中返回以下三种状态:

  • RocketMQLocalTransactionState.COMMIT:提交事务,允许消费者消费该消息
  • RocketMQLocalTransactionState.ROLLBACK:回滚事务,消息将被丢弃不允许消费。
  • RocketMQLocalTransactionState.UNKNOWN:暂时无法判断状态,等待固定时间以后Broker端根据回查规则向生产者进行消息回查。

  checkLocalTransaction是由于二次确认消息没有收到,Broker端回查事务状态的方法。回查规则:本地事务执行完成后,若Broker端收到的本地事务返回状态为RocketMQLocalTransactionState.UNKNOWN,或生产者应用退出导致本地事务未提交任何状态。则Broker端会向消息生产者发起事务回查,第一次回查后仍未获取到事务状态,则之后每隔一段时间会再次回查。

5.2、checkLocalTransaction不回调

  一般来说的原因:

  • 在springboot整合rocketmq,和直接使用rocketmq实现的接口是不一样的,具体看上一小点
  • 编码错误,不会模拟情景,rocketmq未收到半事务提交的结果(Commit或是Rollback),才会进行回查
  • 最大的一个可能是,你使用springboot整合rocketmq时的版本和服务端的版本不一致(我遇到过),比如我这里整合版本是2.2.3,对应的rocketmq的版本是5.0.0,所以我的服务端,肯定也安装一个5.0的版本。如果服务端是4.x,就会出现消息转化报错,从而无法回调,具体可以看broker的日志
  • 参数配置,比如(transactionCheckEnable=truetransactionCheckInterval=15000),是不是配置关闭,或者检查时间过长
  • 测试不用心,比如写了单元测试,测试完,程序就结束了,导致服务端无法检查,所以我的测试程序,都休眠了一会

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

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

相关文章

「Qt Widget中文示例指南」如何实现一个分组框

Qt 是目前最先进、最完整的跨平台C开发工具。它不仅完全实现了一次编写&#xff0c;所有平台无差别运行&#xff0c;更提供了几乎所有开发过程中需要用到的工具。如今&#xff0c;Qt已被运用于超过70个行业、数千家企业&#xff0c;支持数百万设备及应用。 Group Box&#xff…

python中for与while的区别是什么

Python中for循环和while循环本质上是没有区别的&#xff0c;但是在实际应用上&#xff0c;针对性不太一样。 for主要应用在遍历中&#xff0c;比如&#xff1a; example1&#xff1a; for i in range(10):print(i) 打印结果为&#xff1a; 0 1 2 3 4 5 6 7 8 9 注&#xff1a;…

springboot系列-api接口请求实现

springboot HTTP请求接口实现 基于springboot 2.6.6 代码地址&#xff1a;github仓库地址 更多系列教程请关注公众号’coderlike’ 如果觉得有帮助希望能关注下公众号 <parent><groupId>org.springframework.boot</groupId><artifactId>spring-b…

IP网络对讲广播系统审计

前言 这个系统是前两年在一个内网遇到的&#xff0c;当时顺手试了一个admin登陆之后再没有然后了&#xff0c;最近发现有大佬分享关于这个系统的漏洞&#xff0c;于是就把自己当初看的几个漏洞分享一下&#xff0c;系统比较简单&#xff0c;漏洞点很多&#xff0c;不要做坏事哦…

PaddleVideo:PP-TSM 视频分类

本文记录&#xff1a;使用Paddle框架训练TSM&#xff08;Temporal Shift Module&#xff09; 前提条件&#xff1a;已经安装Paddle和PadleVideo&#xff0c;具体可参考前一篇文章。 1-数据准备&#xff1a; 以UCF101为例&#xff1a;内含13320 个短视频&#xff0c;视频类别&…

uniapp引入微信小程序版本VantUI,使用VantUI的自定义tabbar,并解决自定义tabbar出现闪烁的情况

1.uniapp引入微信小程序版本VantUI 去vant官网下载源码&#xff0c;源码放在github&#xff0c;自行去下载下来 https://vant-contrib.gitee.io/vant-weapp/#/home 在pages.json的globalStyle里面注册组件 "globalStyle": {"navigationBarTextStyle": &qu…

zookeeper源码(12)命令行客户端

zkCli.sh脚本 这个命令行脚本在bin目录下: ZOOBIN="${BASH_SOURCE-$0}" ZOOBIN="$(dirname "${ZOOBIN}")" ZOOBINDIR="$(cd "${ZOOBIN}"; pwd)"# 加载zkEnv.sh脚本 if [ -e "$ZOOBIN/../libexec/zkEnv.sh" ]; …

程序员开展副业的有效方法

目录 1 项目咨询1.1 建立个人品牌和专业形象1.2 寻找潜在客户1.3 提供定制化的技术咨询方案 2 软件开发2.1 加入平台寻找项目2.2 展示个人作品2.3 与客户保持良好沟通 3 传授编程知识3.1 选择适合的分享平台3.2 创作有价值的内容3.3 与观众保持互动 4 教育培训4.1 利用在线教育…

RuoYi-Vue若依框架-在框架内用颜色选择器,页面显示色块

在用若依框架进行二次开发的时候写到自己的一个模块&#xff0c;其中涉及到颜色&#xff0c;我就想着是手动输入还是采用颜色选择器呢&#xff0c;考虑到后续涉及到另一个字段编码于时就采用了颜色选择器&#xff0c;选择完的颜色显示的是十六进制的颜色选择器&#xff0c;这时…

零基础学鸿蒙开发可以吗?看完这份鸿蒙入门学习资料就够了!

一、面向人群 1、在校学生、应届毕业生 2、转行人员&#xff0c;希望赶上时代风口&#xff0c;成功求职、转行 3、IT相关工作者&#xff0c;想快速提升技能&#xff0c;升职加薪的朋友 ps&#xff1a;文末可以申请免费试学 二、学习路线 HarmonyOS基础技能HarmonyOS就业…

数据库引论:3、中级SQL

3.中级SQL 一些更复杂的查询表达 3.1 连接表达式 拼接多张表的几种方式 3.1.1 自然连接 natural join&#xff0c;自动连接在所有共同属性上相同的元组 join… using( A 1 , A 2 , ⋯ A_1,A_2,\cdots A1​,A2​,⋯):使用括号里的属性进行自然连接&#xff0c;除了这些属性…

rsync+inotify组合实现及时远程同步

目录 Rsync&#xff08;Remote Sync&#xff09;简介&#xff1a; Rsync 主要特点&#xff1a; Rsync 常用命令选项&#xff1a; Inotify 简介&#xff1a; Inotify 的主要功能&#xff1a; 结合 Rsync 和 Inotify 实现实时同步&#xff1a; 操作步骤&#xff1a; 配置…

蓝桥杯第六届c++大学B组详解

前言&#xff1a; 看了很多博客以及视频讲解&#xff0c;感觉都不是很清楚&#xff0c;比较模棱两可&#xff0c;所以干脆自己一边想&#xff0c;一边写博客&#xff0c;也可帮助到其他人&#xff0c;都是根据自己的逻辑来尽量清楚简单的讲清楚题目&#xff0c;喜欢的不要吝啬三…

RequestMapping注解

一、RequestMapping的作用 RequestMapping 注解是 Spring MVC 框架中的一个控制器映射注解&#xff0c;用于将请求映射到相应的处理方法上。具体来说&#xff0c;它可以将指定 URL 的请求绑定到一个特定的方法或类上&#xff0c;从而实现对请求的处理和响应。 二、RequestMappi…

互联网需要做安全防护吗?

互联网需要做安全防护&#xff0c;因为网络攻击的风险随时存在。一旦遭受大规模攻击&#xff0c;企业很可能会受到严重影响&#xff0c;甚至会造成巨大的经济损失和品牌声誉受损。因此&#xff0c;建议企业在安全防护方面做好以下几点&#xff1a; 加强网络安全意识教育&#x…

linux基础篇:Linux中磁盘的管理(分区、格式化、挂载)

Linux中磁盘的管理&#xff08;分区、格式化、挂载&#xff09; 一、认识磁盘 1.1 什么是磁盘 磁盘是一种计算机的外部存储器设备&#xff0c;由一个或多个覆盖有磁性材料的铝制或玻璃制的碟片组成&#xff0c;用来存储用户的信息&#xff0c;这种信息可以反复地被读取和改写…

python WAV音频文件处理—— (2)处理PCM音频-- waveio包

破译 PCM-Encoded 的音频样本 这部分将变得稍微高级一些&#xff0c;但从长远来看&#xff0c;它将使在 Python 中处理 WAV 文件变得更加容易。 在本教程结束时&#xff0c;我们将构建出 waveio 包&#xff1a; waveio/ │ ├── __init__.py ├── encoding.py ├── met…

在git上先新建仓库-把本地文件提交远程

一.在git新建远程项目库 1.选择新建仓库 以下以gitee为例 2.输入仓库名称&#xff0c;点击创建 这个可以选择仓库私有化还公开权限 3.获取仓库clone链接 这里选择https模式就行&#xff0c;就不需要配置对电脑进行sshkey配置了。只是需要每次提交输入账号密码 二、远…

解决网站“不安全”、“不受信”、“排名下降”,你需要——「SSL证书」

在网络时代&#xff0c;确保网站用户数据安全显得愈发关键。SSL证书作为网络安全的关键要素&#xff0c;对网站而言具有重大意义。 SSL&#xff08;Secure Sockets Layer&#xff09;证书是一种数字证书&#xff0c;用于加密和验证网络通信。它存在于客户端&#xff08;浏览…

【小白学机器学习12】假设检验之3:t 检验 (t检验量,t分布,查t值表等)

目录 1 t 检验的定义 1.1 来自维基百科和百度百科 1.2 别名 1.3 和其他检验的区别 2 适用情况&#xff1a; 2.1 关于样本情况 2.2 适合检查的情况 2.2.1 单样本均值检验&#xff08;One-sample t-test&#xff09; 2.2.2 两独立样本均值检验&#xff08;Independent …