DataX实战:从MongoDB到MySQL的数据迁移--修改源码并测试打包

news2024/11/15 9:02:08

        在现代数据驱动的业务环境中,数据迁移和集成是常见的需求。DataX,作为阿里云开源的数据集成工具,提供了强大的数据同步能力,支持多种数据源和目标端。本文将介绍如何使用DataX将数据从MongoDB迁移到MySQL。

环境准备

  1. 安装MongoDB:首先,我们需要安装MongoDB。通过创建repo文件并配置yum源,我们可以轻松地通过yum安装MongoDB。此外,还需要修改MongoDB的配置文件以允许远程连接,并启动MongoDB服务。

  2. MongoDB可视化工具:为了方便数据操作,我们可以使用MongoDB可视化工具进行数据管理。

MongoDB在Linux系统中的安装与配置指南-CSDN博客

数据准备

创建表和添加测试数据

        在MongoDB中创建必要的表并添加测试数据。可以使用AIGC工具生成插入语句或使用Python代码进行数据导入。

数据如下:

6685758046e0fb0001dad8e8,340030000B47363438383733,8C780D32F900260383493808CC96,2024-07-04 00:00:00 055
6685758046e0fb0001dad8e9,340030000B47363438383733,8C79A06C39EE65FC81D828307124,2024-07-04 00:00:00 055
6685758046e0fb0001dad8ea,340030000B47363438383733,8C79A06C39EE632C2C12766ABC7D,2024-07-04 00:00:00 055
6685758046e0fb0001dad8eb,340030000B47363438383733,8C780D32381A65EEB9D6ACD107E7,2024-07-04 00:00:00 055
6685758046e0fb0001dad8ec,340030000B47363438383733,8C79A06C39EE65FC83D8242B91FC,2024-07-04 00:00:00 055
6685758046e0fb0001dadb53,180025000847363438383733,02818334223D7A,2024-07-04 00:00:00 125
6685758046e0fb0001dadb54,180025000847363438383733,8C7813B93818F058371851BB46ED,2024-07-04 00:00:00 125
6685758046e0fb0001dadb55,180025000847363438383733,A8001BAF809CEF25E00492C097AD,2024-07-04 00:00:00 125
6685758046e0fb0001dadb56,180025000847363438383733,8D78046A990C8E9DF09019F5FFD9,2024-07-04 00:00:00 125
6685758046e0fb0001dadb57,180025000847363438383733,02C18CB2F5ACA1,2024-07-04 00:00:00 125
6685758046e0fb0001dadb58,180025000847363438383733,200016303DA8AC,2024-07-04 00:00:00 125
6685758046e0fb0001dadb59,180025000847363438383733,02C18CB2F5ACA1,2024-07-04 00:00:00 125
6685758046e0fb0001dadb5a,180025000847363438383733,02C189B8C3FFB4,2024-07-04 00:00:00 125
6685758046e0fb0001dadb5b,180025000847363438383733,8D89805E584FE2AC38F4F65130D7,2024-07-04 00:00:00 125
6685758046e0fb0001dadb5c,180025000847363438383733,02A185BA442656,2024-07-04 00:00:00 125
6685758046e0fb0001dadb5d,180025000847363438383733,8D7805AF9909180C18041613AFAB,2024-07-04 00:00:00 125
6685758046e0fb0001dadb5e,180025000847363438383733,02E18D1AB8F754,2024-07-04 00:00:00 125
6685758046e0fb0001dadb5f,180025000847363438383733,02A184B1B5AC11,2024-07-04 00:00:00 125
6685758046e0fb0001dadb60,180025000847363438383733,80618193580D32DD1EC5D965CAAF,2024-07-04 00:00:00 125
6685758046e0fb0001dadb61,180025000847363438383733,A000019389C80030A40000B08473,2024-07-04 00:00:00 125
6685758046e0fb0001dadb62,180025000847363438383733,A8001235FF731F13FFF453FB3E9D,2024-07-04 00:00:00 125
6685758046e0fb0001dadb63,180025000847363438383733,A00015BDC2980030A400000C9499,2024-07-04 00:00:00 125
6685758046e0fb0001dadb64,180025000847363438383733,02A18639AEDAAD,2024-07-04 00:00:00 125
6685758046e0fb0001dadb65,180025000847363438383733,8D780E409908D120F0482094F4EF,2024-07-04 00:00:00 125
6685758046e0fb0001dadb66,180025000847363438383733,5D75021BAFC19A,2024-07-04 00:00:00 125
6685758046e0fb0001dadb67,180025000847363438383733,02C18930C484A8,2024-07-04 00:00:00 125
6685758046e0fb0001dadb68,180025000847363438383733,A00015BDFFD9F93B2004E186573A,2024-07-04 00:00:00 125

 示例:

db.yourCollectionName.insertOne({  
    "id": "6685758046e0fb0001dad8e8",  
    "serialNumber": "340030000B47363438383733",  
    "uniqueId": "8C780D32F900260383493808CC96",  
    "timestamp": "2024-07-04T00:00:00.055Z"  
})

数据导入方式

介绍了两种数据导入方式,一种是使用Python代码导入,另一种是通过命令行导入。

使用 python 代码导入

pip install pymongo==4.4

from pymongo import MongoClient

# 创建MongoDB连接
client = MongoClient('hadoop13', 27017)

# 选择数据库,如果不存在则会自动创建
db = client['demo']

# 选择集合,如果不存在则会自动创建
collection = db['y_demo']

# 插入数据
#rawDataContent,revTime,deviceCode

with open('测试数据','r') as file1:
    for line in file1:
        arr = line.split(',')
        print(arr)
        dict = {"rawDataContent": arr[2], "revTime": arr[3].rstrip('\n'), "deviceCode": arr[1]}
        print(dict)
        collection.insert_one(dict)

使用命令导入

如果不会 python,也可以通过命令导入:

mongoimport -h 127.0.0.1 -d demo -c y_demo --file "/home/y_demo.json" --jsonArray

json 数据在本文绑定资源可下载

DataX实战

真实需求

        将MongoDB中的一个表的三个字段导入到ClickHouse中,并在导入过程中将一个字段拆分为三个字段,同时增加三个新字段,变为 6 个字段。

解决方案

通过修改DataX的MongoDB reader源码来实现这一需求。

源码修改

详细介绍了如何使用IDEA打开DataX源码,修改maven配置,下载必要的jar包,并进行源码的修改和测试。

Datax - mongodb reader

DataX/mongodbreader/doc/mongodbreader.md at master · alibaba/DataX · GitHub

DataX案例:读取MongoDB的数据导入MySQL - 架构艺术 - 博客园 (cnblogs.com)

源码导入

环境准备

使用IntelliJ IDEA打开DataX源码。配置本地Maven,以加快依赖包的下载速度。

下载 jar 包的过程时间有点长,请耐心等待,本身是不大的,大约 20 多 M,但如果你拿到是含有编译过的 target 文件夹的源码,大约有 6G。

分析需求

阅读MongoDBReader的源码,理解其数据抽取和转换的机制。

首先同事已经通过 java 代码将 mongodb 的数据写入到了 ck 之中,想让你通过 datax 进行数据的抽取。同事的代码已经给了:

package com.lzhy.platform.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.HexUtil;
import com.lzhy.clickhouse.template.ClickHouseTemplate;
import com.lzhy.platform.entity.ParseData;
import com.lzhy.platform.model.pojo.CkAdsbParseData;
import com.lzhy.platform.model.pojo.CkAdsbRawData;
import com.lzhy.platform.model.pojo.DecodeSaveData;
import com.lzhy.platform.model.pojo.SendKafkaMessage;
import com.lzhy.platform.service.IWorkService;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.LongAdder;
import java.util.stream.Collectors;


@Service("workService")
@Slf4j
@RequiredArgsConstructor
public class WorkServiceImpl implements IWorkService {

    private final ClickHouseTemplate<CkAdsbRawData> rawDataClickHouseTemplate;

    private final ClickHouseTemplate<CkAdsbParseData> ckAdsbParseDataClickHouseTemplate;

    public static final String PARSE_TABLE_NAME = "default.adsb_parse_temp_local";

    /**
     * 原始数据表名
     */
    public static final String RAW_TABLE_NAME = "default.adsb_raw_data_local";

    /**
     * 原始数据计数器 统计消息个数
     */
    private final LongAdder rawDataCount = new LongAdder();
    /**
     * 解析数据计数器 统计消息个数
     */
    private final LongAdder parseDataCount = new LongAdder();

    /**
     * 原始数据临时存储
     */
    @Getter
    private final List<CkAdsbRawData> rawDataList = new ArrayList<>(2000);
    /**
     * 解析数据临时存储
     */
    @Getter
    private final List<CkAdsbParseData> ckParseDataList = new ArrayList<>(2000);

    @Override
    public void start() {
    }

    @Override
    public void saveRawDate(SendKafkaMessage sendKafkaMessage) {
        try {
            List<String> list = sendKafkaMessage.getRawDataValue();
            String deviceCode = sendKafkaMessage.getDeviceCode();
            long revTime = sendKafkaMessage.getRevTime();

            if (CollUtil.isEmpty(list) || Objects.isNull(deviceCode)) {
                return;
            }

            List<CkAdsbRawData> res = list.stream()
            .filter(StringUtils::hasLength)
            .map(raw -> {
                String[] split = raw.split(",");
                String rawContent = split[0];
                long time = Long.parseLong(split[1]);
                CkAdsbRawData ckAdsbRawData = new CkAdsbRawData();
                ckAdsbRawData.setIcao(getIcao(rawContent));
                ckAdsbRawData.setRevTime(LocalDateTimeUtil.of(time));
                ckAdsbRawData.setHandleTime(LocalDateTimeUtil.now());
                ckAdsbRawData.setDeviceCode(deviceCode);
                ckAdsbRawData.setMsgContent(rawContent);
                        ckAdsbRawData.setMsgType(getDfType(rawContent));
                        return ckAdsbRawData;
                    }).collect(Collectors.toList());

            rawDataCount.increment();
            rawDataList.addAll(res);
            if (rawDataCount.longValue() % 15 == 0) {
                //存储
                log.info("原始数据存储。存储大小:{}", ckParseDataList.size());
                rawDataClickHouseTemplate.insertBath(RAW_TABLE_NAME, rawDataList);
                rawDataList.clear();
                rawDataCount.reset();
            }
        } catch (Exception e) {
            log.error("储存失败", e);
        }
    }

    @Override
    public void saveParseDate(DecodeSaveData decodeSaveData) {
        if (Objects.isNull(decodeSaveData)) {
            return;
        }
        List<ParseData> parseDataList = decodeSaveData.getParseDataList();
        if (CollUtil.isEmpty(parseDataList)) {
            return;
        }
        List<CkAdsbParseData> res = parseDataList.stream().map(parseData -> {
            CkAdsbParseData ckAdsbParseData = new CkAdsbParseData();
            ckAdsbParseData.setIcao(Integer.parseInt(parseData.getIcao(), 16));
            ckAdsbParseData.setRevTime(LocalDateTimeUtil.of(parseData.getRevTime()));
            ckAdsbParseData.setDeviceCode(parseData.getDeviceCode());
            ckAdsbParseData.setType(parseData.getType());
            ckAdsbParseData.setRegNo(parseData.getRegNo());
            ckAdsbParseData.setCallsign(parseData.getCallsign());
            ckAdsbParseData.setCountry(parseData.getCountry());
            ckAdsbParseData.setCompany(parseData.getCompany());
            ckAdsbParseData.setLat(parseData.getLat());
            ckAdsbParseData.setLng(parseData.getLng());
            ckAdsbParseData.setAltitude(parseData.getAltitude());
            ckAdsbParseData.setHeading(parseData.getHeading());
            ckAdsbParseData.setSpeed(parseData.getSpeed());
            ckAdsbParseData.setPositionTime(parseData.getPositionTime().getTime());
            ckAdsbParseData.setSpeedTime(parseData.getSpeedTime() == null ? 0L : parseData.getSpeedTime().getTime());
            ckAdsbParseData.setVerSpeed(parseData.getVerSpeed());
            ckAdsbParseData.setVerSpeedType(parseData.getVerSpeedType());
            ckAdsbParseData.setHeight(parseData.getHeight());
            ckAdsbParseData.setHandleTime(LocalDateTime.now());
            ckAdsbParseData.setACode(parseData.getaCode());
            ckAdsbParseData.setIsOnGround(parseData.getIsOnGround());
            ckAdsbParseData.setSpi(parseData.getSpi());
            ckAdsbParseData.setEmergency(parseData.getEmergency());
            ckAdsbParseData.setAlert("");
            ckAdsbParseData.setRegNo(parseData.getRegNo());
            return ckAdsbParseData;
        }).collect(Collectors.toList());

        parseDataCount.increment();
        ckParseDataList.addAll(res);
        if (parseDataCount.longValue() % 20 == 0) {
            //存储
            try {
                log.info("解析数据存储。存储大小:{}", ckParseDataList.size());
                ckAdsbParseDataClickHouseTemplate.insertBath(PARSE_TABLE_NAME, ckParseDataList);
            } catch (Exception e) {
                log.error("存储失败", e);
            }
            ckParseDataList.clear();
            parseDataCount.reset();
        }
    }

    /**
     * 获取icao
     *
     * @param rawContent
     * @return
     */
    private int getIcao(String rawContent) {
        int dfType = getDfType(rawContent);
        if (dfType == 4 || dfType == 5) {
            return getShortIcao(HexUtil.decodeHex(rawContent));
        }
        String icaoStr = rawContent.substring(2, 8);
        return Integer.parseInt(icaoStr, 16);
    }

    private final long CRC24_INIT = 0x0;
    private final long CRC24_POLY = 0x1FFF409;

    /**
     * 获取 04 05 报文icao
     *
     * @param abMessage
     * @return
     */
    private int getShortIcao(byte[] abMessage) {
        long ulCRC = 0;
        ulCRC = CRC24_INIT;
        for (int i = 0; i < abMessage.length - 3; i++) {
            long tem = abMessage[i];
            tem = tem << 16;
            ulCRC = ulCRC ^ tem;
            for (int j = 0; j < 8; j++) {
                ulCRC = ulCRC << 1;
                if ((ulCRC & 0x1000000) != 0) {
                    ulCRC = ulCRC ^ CRC24_POLY;
                }
            }
        }
        long last3Bits = abMessage[4] * 0x10000 + abMessage[5] * 0x100 + abMessage[6];
        String hex = HexUtil.toHex((ulCRC ^ last3Bits));
        hex = hex.length() > 6 ? hex.substring(hex.length() - 6) : hex;
        return Integer.parseUnsignedInt(hex, 16);
    }

    /**
     * 获取df类型
     *
     * @param rawContent
     * @return
     */
    private int getDfType(String rawContent) {
        String substring = rawContent.substring(0, 2);
        return Integer.parseInt(substring, 16) >> 3;
    }
}

因为人家代码中用到了 hutool 工具类,所以我们在源码的坐标中有添加该坐标:

<dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.16</version>
</dependency>

修改源码并测试打包

在修改完源码后,需要进行编译和打包。文章中提供了详细的编译命令和可能遇到的编译错误及其解决方案。

修改源码

所有字段全部写死

if (tempCol == null) {
    //continue; 这个不能直接continue会导致record到目的端错位
    String columnName = column.getString(KeyConstant.COLUMN_NAME);
    if ("icao".equals(columnName)){
        record.addColumn(new LongColumn(getIcao(item.getString("rawDataContent"))));
    }else if("msg_type".equals(columnName)){
        record.addColumn(new LongColumn(getDfType(item.getString("rawDataContent"))));
    }else if("handle_time".equals(columnName)){
        record.addColumn(new StringColumn(DateUtil.now()));
    }else{
        record.addColumn(new StringColumn(null));
    }
}
打包上传

代码编写完之后,需要编译,打包上传:

对datax的所有模块进行打包,时间比较长 30 分钟左右 【该命令会将 datax 中的所有插件全部打包】

mvn -U clean package assembly:assembly '-Dmaven.test.skip=true'

指定mongodbreader模块 以及 它所依赖的模块进行打包 【推荐使用,大约只运行 3 分钟左右】

mvn -U clean package -pl mongodbreader -am  assembly:assembly '-Dmaven.test.skip=true'

-p1 表示只打包对应的模块 -am 表示对应模块关联的模块也要打包编译。

编译报错

看到这个错误,是 java 环境变量的问题,这个问题非常难找,配置如下:

配置 CLASSPATH:

配置 JAVA_HOME:

配置 PATH 路径:

然后继续执行编译打包名命令,成功!

将idea中打的jar包上传到datax的mongodbreader下,替换原本的插件jar包

此时如果运行 job 任务,会报错,因为会提示缺 hutool 工具的 jar 包

hutool工具类jar包上传到datax的mongodbreader的libs目录下

出现这种错误

 DataX实战之MongoDB导入数据到mysql——打包jar包时出现Could not find goal assembly in plugin org.apache.maven.plugins_datax mongodbreader源码-CSDN博客

测试一下

在完成源码修改和打包后,需要在MySQL中创建相应的表,并编写DataX的JSON配置文件进行测试运行。

mysql建表
create table y_demo(
  device_code varchar(100),
  rev_time  varchar(100),
  msg_content  varchar(100),
  icao  varchar(100),
  msg_type  varchar(100),
  handle_time  varchar(100)
)

 

编写datax的json文件,并且测试运行

测试 json

{
    "job": {
        "content": [
            {
                "reader": {
                    "name": "mongodbreader",
                    "parameter": {
                        "address": ["bigdata01:27017"],
                        "collectionName": "y_demo",
                        "column": [
                         {
                         "name":"deviceCode",
                         "type":"string"
                         },
                         {
                         "name":"revTime",
                         "type":"string"
                         },
                         {
                         "name":"rawDataContent",
                         "type":"string"
                         },
                         {
                         "name":"icao",
                         "type":"string"
                         },
                         {
                         "name":"msg_type",
                         "type":"string"
                         },
                         {
                          "name":"handle_time",
                          "type":"string"
                         }
                        ],
                        "dbName": "demo",
                    }
                },
                "writer": {
                    "name": "mysqlwriter",
                    "parameter": {
                        "column": ["device_code","rev_time","msg_content","icao","msg_type","handle_time"],
                        "connection": [
                            {
                                "jdbcUrl": "jdbc:mysql://bigdata01:3306/sqoop",
                                "table": ["y_demo"]
                            }
                        ],
                        "password": "123456",
                        "username": "root",
                        "writeMode": "insert"
                    }
                }
            }
        ],
        "setting": {
            "speed": {
                "channel": "1"
            }
        }
    }
}
运行报错

添加 jar 包

运行 json 脚本,导入成功

mysql 中的数据如下

资料

Datax mongodbreader源码jar包 ,替换/opt/installs/datax/plugin/reader/mongodbreader/

自定义函数的jar包 /opt/installs/datax/plugin/reader/mongodbreader/libs

hutool工具类 /opt/installs/datax/plugin/reader/mongodbreader/libs

fastjson2 的 jar 包

通过网盘分享的文件:datax-mongo-1.0-SNAPSHOT.jar等4个文件

 视频讲解链接

通过修改DataX源码解决Mongodb导入数据到ClickHouse的问题_哔哩哔哩_bilibili

结语

        DataX提供了一个简单而有效的方法来迁移MongoDB数据到MySQL。通过编写适当的JSON配置文件,我们可以灵活地处理各种复杂的数据迁移任务。这不仅提高了DataX的可用性,也为我们的数据同步工作提供了更多的可能。

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

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

相关文章

从0新建一个微信小程序实现一个简单跳转

首先 1.从这里下载开发工具 https://developers.weixin.qq.com/miniprogram/dev/framework/quickstart/getstart.htm 2. 等下载完毕后 创建一个空白项目 在pages目录下右键创建一个page : testUI,这时候会生成四个文件 新建一个文件夹 testUI 给他们放一起 3.增加一个按钮 …

实战OpenCV之图像滤波

基础入门 图像滤波是数字图像处理中一种非常重要的技术&#xff0c;主要用于图像噪声去除、图像平滑、突出图像特征&#xff0c;或者进行图像风格的转换。它通过数学运算对图像中的像素值进行修改&#xff0c;以达到特定的处理目的。图像滤波可以分为两大类&#xff0c;分别为&…

matlab划分区域的等高线云图(代码)

出图结果如下&#xff1a; 代码如下&#xff0c;按需修改 clear;clc; numRows100; %数据区域&#xff0c;步长&#xff0c;步数 numCols100; ax-2;bx2; ay-2;by2; hx(bx-ax)/numCols; hy(by-ay)/numRows; XXCax:hx:bx; %坐标阵&#xff0c;data Y…

Ubuntu磁盘不足扩容

1.问题 Ubuntu磁盘不足扩容 2.解决方法 安装一下 sudo apt-get install gpartedsudo gparted

如何使用 Bittly 为基于 HTTP 的 API 快速创建 UI 操作界面

在开发 Web 应用或服务时&#xff0c;通常会提供不同数量的 API 接口给客户端或其他第三方使用&#xff0c; 当 API 数量达到一定数量的时候&#xff0c;在处理接口间的调用链以及参数关系时就会变得异常麻烦。 在这种情况下便可通过 Bittly 的面板功能将这些 API 结构进行组装…

vue3的生命周期有哪些

vue3的生命周期&#xff1a;1、beforecreate&#xff1b;2、created&#xff1b;3、beforemount&#xff1b;4、mounted&#xff1b;5、beforeupdate&#xff1b;6、updated&#xff1b;7、beforedestroy&#xff1b;8、destroyed&#xff1b;9、activated&#xff1b;10、deac…

洛谷-P5461 赦免战俘(Java递归)

题目背景 借助反作弊系统&#xff0c;一些在月赛有抄袭作弊行为的选手被抓出来了&#xff01; 题目描述 样例 #1 样例输入 #1 3样例输出 #1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 1 0 0 0 0 0 1 0 1 0 0 0 0 1 1 1 1 0 0 0 1 0 0 0 1 0 0 1 1 0 0 1 1 0 1 0 1 0 1 0 1 1 1 1 1 1…

【机器学习】过拟合与欠拟合——如何优化模型性能

【机器学习】过拟合与欠拟合——如何优化模型性能 1. 引言 在机器学习中&#xff0c;模型的表现不仅依赖于算法的选择&#xff0c;还依赖于模型对数据的拟合情况。过拟合&#xff08;Overfitting&#xff09;和欠拟合&#xff08;Underfitting&#xff09;是模型训练过程中常…

黑马智数Day4-1

新增月卡 配置路由完成跳转 {path: /cardAdd,component: () > import(/views/car/car-card/add-card) }<el-button type"primary" click"$router.push(/cardAdd)">添加月卡</el-button> 车辆信息表单验证 <el-form :model"carInf…

自定义安装WSL和WSL迁移到指定位置

安装 WSL 到指定磁盘 配置环境 打开控制面板&#xff0c;找到程序–>右击启用或关闭Windows功能 向下滑动&#xff0c;找到“适用于Linux的Windows子系统”和“虚拟机平台”两个选项&#xff0c;勾选上&#xff0c;然后重启电脑 安装Ubuntu20.04 1. 下载发行版 打开链接…

全能通人工智能的能力评估框架-Levels of AGI: Operationalizing Progress on the Path to AGI

译自’Levels of AGI: Operationalizing Progress on the Path to AGI’&#xff0c;有所删节.笔者能力有限&#xff0c;敬请勘误。 摘要 Google DeepMind提出一种针对通用人工智能 (Artificial General Intelligence, 简称AGI) 框架&#xff0c;该框架用于评估AGI的模型及早期…

CAPL—on signal到底该怎么玩?

总结&#xff1a;一个前提&#xff0c;两种形式&#xff0c;一个注意&#xff0c;外加一个很不常用的知识点 1&#xff1a;一个前提&#xff1a;必须是DBC或其他数据库文件中定义的信号&#xff0c;且这个数据库已经添加到工程中去了。 2&#xff1a;使用格式 on signal&…

如何修改音频的音量增益

一、前言 在开发音频相关的功能&#xff08;比如说语音通话、播放音乐&#xff09;时&#xff0c;经常会遇到音量太小的问题&#xff0c;这时候就需要我们对原始数据进行处理。本文将介绍如何通过修改原始音频数据来增加增益&#xff0c;本文包含如下内容&#xff1a; 1.音频数…

3D Slicer医学图像全自动AI分割组合拳-MONAIAuto3DSeg扩展

3D Slicer医学图像全自动AI分割组合拳-MONAIAuto3DSeg扩展 1 官网下载最新3D Slicer image computing platform | 3D Slicer 版本5.7 2 安装torch依赖包&#xff1a; 2.1 进入安装目录C:\Users\wangzhenlin\AppData\Local\slicer.org\Slicer 5.7.0-2024-09-21\bin&#xff0…

PostgreSQL技术内幕12:PostgreSQL事务原理解析-锁管理

0.简介 本文介绍PG中的锁技术&#xff0c;主要包括PG中两阶段锁的介绍和PG中各种不同级别的锁&#xff0c;死锁问题介绍&#xff0c;以及如何去查看锁。 1.PG中两阶段锁 1.1 需要锁机制的原因 PG中的隔离性是通过MVCC和两阶段锁实现的&#xff0c;有了MVCC为什么还要使用悲…

python全栈学习记录(十八)re、os和sys、subprocess

re、os和sys、subprocess 文章目录 re、os和sys、subprocess一、re1.正则字符2.正则表达式的使用3.group的使用4.贪婪匹配与惰性匹配5.其他注意事项 二、os和sys1.os2.sys 三、subprocess四、打印进度条 一、re python中的re模块用来使用正则表达式&#xff0c;正则就是用一系…

基于Springboot企业员工人事管理系统JAVA|VUE|SSM计算机毕业设计源代码+数据库+LW文档+开题报告+答辩稿+部署教+代码讲解

源代码数据库LW文档&#xff08;1万字以上&#xff09;开题报告答辩稿 部署教程代码讲解代码时间修改教程 一、开发工具、运行环境、开发技术 开发工具 1、操作系统&#xff1a;Window操作系统 2、开发工具&#xff1a;IntelliJ IDEA或者Eclipse 3、数据库存储&#xff1a…

研一上课计划2024/9/23有感

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、需要认真上课的1.应用数理统计&#xff08;开卷考试&#xff09;2.最优化方法&#xff08;开卷考试&#xff09;3.跨文化交际&#xff08;主题演讲20课堂讨…

基于SpringBoot和Vue的餐饮管理系统

基于springbootvue实现的餐饮管理系统 &#xff08;源码L文ppt&#xff09;4-078 第4章 系统设计 4.1 总体功能设计 一般个人用户和管理者都需要登录才能进入餐饮管理系统&#xff0c;使用者登录时会在后台判断使用的权限类型&#xff0c;包括一般使用者和管理者,一…

手写SpringMVC(简易版)

在上一篇博客中说到这里我们要进行手写SpringMVC&#xff0c;因此最好是将上一篇博客中的SpringMVC源码分析那一块部分搞懂&#xff0c;或者观看动力节点老杜的SpringMVC源码分析再来看这里的书写框架。 首先我们要知道对于一个完整系统的参与者&#xff08;即一个完整的web项…