Flink CDC 同步 Mysql 数据

文章目录

      • 一、Flink CDC、Flink、CDC各有啥关系
        • 1.1 概述
        • 1.2 和 jdbc Connectors 对比
      • 二、使用
        • 2.1 Mysql 打开 bin-log 功能
        • 2.2 在 Mysql 中建库建表准备
        • 2.3 遇到的坑
        • 2.4 测试
      • 三、番外

一、Flink CDC、Flink、CDC各有啥关系

  Flink:流式计算框架,不包含 Flink CDC,和 Flink CDC没关系

  CDC:是一种思想,理念,不涉及某一门具体的技术。CDC 是变更数据捕获(Change Data Capture)技术的缩写,它可以将源数据库(Source)的增量变动记录,同步到一个或多个数据目的(Sink)。在同步过程中,还可以对数据进行一定的处理,例如过滤、关联、分组、统计等。目前专业做数据库事件接受和解析的中间件是Debezium,如果是捕获Mysql,还有Canal。

  Flink CDC:是 CDC 的一种实现而已,不属于 Flink 子版块。这个技术是阿里开发的。目的是为了丰富 Flink 的生态。

1.1 概述

  Flink CDC 基于数据库日志的 Change Data Caputre 技术,实现了全量和增量的一体化读取能力,并借助 Flink 优秀的管道能力和丰富的上下游生态,支持捕获多种数据库的变更,并将这些变更实时同步到下游存储。

1.2 和 jdbc Connectors 对比

  JDBC Connectors 连接器,确实可以读取外部的 数据库。比如:MySQL、Oracle、SqlServer等。但是,JDBC连数据库,只是瞬时操作,没办法持续监听数据库的数据变化。

  Flink CDC Connectors,可以实现数据库的变更捕获,能够持续不断地把变更数据同步到下游的系统中。

官网概述:https://ververica.github.io/flink-cdc-connectors/
github链接:https://github.com/ververica/flink-cdc-connectors

二、使用

  FlinkCDC 同步数据,有两种方式,一种是 FlinkSQL 的方式,一种是Flink DataStream 和 Table API 的方式。

  我这里直接用的是 ieda 测试的 DataStream 方式。

  代码来自:https://github.com/yclxiao/flink-cdc-demo/tree/main/src/main/java/com/yclxiao/flinkcdcdemo

  CloudAcctProfit2DwsHdjProfitRecordAPI.java

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.ververica.cdc.connectors.mysql.source.MySqlSource;
import com.ververica.cdc.debezium.JsonDebeziumDeserializationSchema;
import com.xiaoqiang.utils.JdbcUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.flink.api.common.eventtime.WatermarkStrategy;
import org.apache.flink.api.common.functions.FilterFunction;
import org.apache.flink.api.common.functions.FlatMapFunction;
import org.apache.flink.configuration.Configuration;
import org.apache.flink.streaming.api.datastream.DataStreamSource;
import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.functions.sink.RichSinkFunction;
import org.apache.flink.util.Collector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.*;

public class CloudAcctProfit2DwsHdjProfitRecordAPI {
    private static final Logger LOG = LoggerFactory.getLogger(CloudAcctProfit2DwsHdjProfitRecordAPI.class);
    private static String MYSQL_HOST = "x.x.x.x";
    private static int MYSQL_PORT = 3306;
    private static String MYSQL_USER = "root";
    private static String MYSQL_PASSWD = "xiaoqiang";
    private static String SYNC_DB = "league_test";
    private static List<String> SYNC_TABLES = Arrays.asList("league_test.oc_settle_profit");

    public static void main(String[] args) throws Exception {
        MySqlSource<String> mySqlSource = MySqlSource.<String>builder()
                .hostname(MYSQL_HOST)
                .port(MYSQL_PORT)
                .databaseList(SYNC_DB) // set captured database
                .tableList(String.join(",", SYNC_TABLES)) // set captured table
                .username(MYSQL_USER)
                .password(MYSQL_PASSWD)
                .deserializer(new JsonDebeziumDeserializationSchema()) // converts SourceRecord to JSON String
                .build();

        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        env.setParallelism(1);
        env.enableCheckpointing(5000);

        DataStreamSource<String> cdcSource = env.fromSource(mySqlSource, WatermarkStrategy.noWatermarks(), "CDC Source" + "xiaoqiang-flink");

        List<String> tableList = getTableList();
        System.out.println("tableList--->"+tableList);
        for (String tbl : tableList) {
            SingleOutputStreamOperator<String> filterStream = filterTableData(cdcSource, "oc_settle_profit");
//            SingleOutputStreamOperator<String> cleanStream = clean(filterStream);
            // 流的数据sink出去
            filterStream.addSink(new CustomDealDataSink())
                    .name("sink " + tbl);
        }
        env.execute("xiaoqiang-flink");
    }

    /**
     * 自定义sink
     */
    private static class CustomDealDataSink extends RichSinkFunction<String> {
        private transient Connection coalitiondbConnection;
        private transient Statement coalitiondbStatement;
        private transient Connection cloudConnection;
        private transient Statement cloudStatement;

        @Override
        public void open(Configuration parameters) throws Exception {
            super.open(parameters);
            // 在这里初始化 JDBC 连接
            coalitiondbConnection = DriverManager.getConnection("jdbc:mysql://x.x.x.x:3306/league_test", "root", "");
            coalitiondbStatement = coalitiondbConnection.createStatement();
            cloudConnection = DriverManager.getConnection("jdbc:mysql://x.x.x.x:3306/cloud_test", "root", "");
            cloudStatement = cloudConnection.createStatement();
        }

        @Override
        public void invoke(String value, Context context) throws Exception {
            // 解析拿到的CDC-JSON数据
            JSONObject rowJson = JSON.parseObject(value);
            String outNo = rowJson.getString("out_no");
            Integer userType = rowJson.getInteger("user_type");
            String id = rowJson.getString("id");
            String payOrderNo = rowJson.getString("pay_order_no");
            String title = rowJson.getString("title");
            String fromUserId = rowJson.getString("from_user_id");
            String fromAccountId = rowJson.getString("from_account_id");
            String userId = rowJson.getString("user_id");
            String accountId = rowJson.getString("account_id");
            Integer amount = rowJson.getInteger("amount");
            Integer profitState = rowJson.getInteger("profit_state");
            Date profitTime = rowJson.getTimestamp("profit_time");
            Integer refundState = rowJson.getInteger("refund_state");
            Date refundTime = rowJson.getTimestamp("refund_time");
            Date addTime = rowJson.getTimestamp("add_time");
            String remark = rowJson.getString("remark");
            String acctCircle = rowJson.getString("acct_circle");
            Integer fromUserType = rowJson.getInteger("from_user_type");
            String companyId = rowJson.getString("company_id");
            String bizCompanyId = rowJson.getString("biz_company_id");
//            if (1 != profitState || !"PG11111".equals(acctCircle)) {
//                return;
//            }
//
//            // 读取相关表的数据(与其他表进行关联)
//            Integer bizType = null;
//            String contributeUserId = null;
//            String relationBrandOwnerId = null;
//            ResultSet virtualOrderResultSet = coalitiondbStatement.executeQuery("select * from tc_virtual_order where order_type != 2 and id = '" + outNo + "'");
//            // 如果是tc_virtual_order订单(上岗卡、安心卡、课程)
//            if (virtualOrderResultSet.next()) {
//                // 处理数据逻辑
//                Integer virtualOrder4OrderType = virtualOrderResultSet.getInt("order_type");
//                String virtualOrder4CompanyId = virtualOrderResultSet.getString("company_id");
//                String virtualOrder4BrandId = virtualOrderResultSet.getString("brand_id");
//                // 上岗卡订单排掉,因为已经有别的任务处理了
//                if (virtualOrder4OrderType == 2) {
//                    return;
//                }
//                // orderType转换
//                if (virtualOrder4OrderType == 6) {
//                    bizType = 10;
//                } else if (virtualOrder4OrderType == 1) {
//                    bizType = 11;
//                } else if (virtualOrder4OrderType == 5) {
//                    bizType = 12;
//                }
//                // userType转换
//                if (virtualOrder4OrderType == 6 && userType == 92) {
//                    contributeUserId = virtualOrder4CompanyId;
//                } else if (virtualOrder4OrderType == 1 && userType == 92) {
//                    contributeUserId = virtualOrder4CompanyId;
//                } else if (virtualOrder4OrderType == 5 && userType == 92) {
//                    contributeUserId = virtualOrder4CompanyId;
//                }
//                // relationBrandOwnerId转换
//                if (virtualOrder4OrderType == 6 && userType == 90) {
//                    relationBrandOwnerId = virtualOrder4BrandId;
//                } else if (virtualOrder4OrderType == 1 && userType == 90) {
//                    relationBrandOwnerId = virtualOrder4BrandId;
//                } else if (virtualOrder4OrderType == 5 && userType == 90) {
//                    relationBrandOwnerId = virtualOrder4BrandId;
//                }
//                // remark转换
//                if (virtualOrder4OrderType == 1 || virtualOrder4OrderType == 5) {
//                    remark = title;
//                }
//            } else {
//                // 如果不是tc_virtual_order的数据,则可能是其他数据,此处只保留好到家实物商品数据
//                if (StringUtils.isBlank(payOrderNo)) {
//                    return;
//                }
//                ResultSet acctPayOrderResultSet = cloudStatement.executeQuery("select * from acct_pay_order t where t.id = '" + payOrderNo + "'");
//                if (!acctPayOrderResultSet.next()) {
//                    return;
//                }
//                Integer payCate = acctPayOrderResultSet.getInt("pay_cate");
//                if (200100 != payCate) { // 好到家实物商品类型
//                    return;
//                }
//
//                bizType = 20;
//                if (userType == 92 && StringUtils.isNotBlank(bizCompanyId)) {
//                    contributeUserId = bizCompanyId;
//                } else if (userType == 90 && StringUtils.isNotBlank(bizCompanyId)) {
//                    ResultSet brandOwnerIdResultSet = cloudStatement.executeQuery("select * from uc_brand_partner t where t.company_id = '" + bizCompanyId + "'");
//                    if (brandOwnerIdResultSet.next()) {
//                        relationBrandOwnerId = brandOwnerIdResultSet.getString("brand_owner_id");
//                    }
//                }
//            }
//            if (StringUtils.isBlank(remark)) {
//                remark = title;
//            }

            // 数据写入到mysql
            String insertSql = "INSERT INTO dws_profit_record_hdj_flink_api (id, show_profit_id, order_no, from_user_id, from_user_type, user_id,\n" +
                    "                                                    user_type, amount, profit_time, state, acct_circle, biz_type,\n" +
                    "                                                    contribute_user_id, relation_brand_owner_id, remark, add_time)\n" +
                    "VALUES ('" + id + "', '" + "JSD" + id + "', '" + outNo + "', '" + fromUserId + "', " + fromUserType + ", '" + userId + "', " + userType + ",\n" +
                    "        " + amount + ", '" + DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss", TimeZone.getTimeZone("GMT")) + "', " + profitState + ", '" + acctCircle + "', " + 1 + ", " + (StringUtils.isBlank("123") ? null : "'" + "contributeUserId" + "'") + ", " + (StringUtils.isBlank("relationBrandOwnerId") ? null : "'" + "relationBrandOwnerId" + "'") + ", '" + remark + "',\n" +
                    "        '" + DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss", TimeZone.getTimeZone("GMT")) + "');";
            cloudStatement.execute("delete from dws_profit_record_hdj_flink_api where id = '" + id + "'");
            System.out.println("insertSql--->"+insertSql);
            cloudStatement.execute(insertSql);
        }

        @Override
        public void close() throws Exception {
            super.close();
            // 在这里关闭 JDBC 连接
            coalitiondbStatement.close();
            coalitiondbConnection.close();
            cloudStatement.close();
            cloudConnection.close();
        }
    }

    /**
     * 清晰数据
     *
     * @param source
     * @return
     */
    private static SingleOutputStreamOperator<String> clean(SingleOutputStreamOperator<String> source) {
        return source.flatMap(new FlatMapFunction<String, String>() {
            @Override
            public void flatMap(String row, Collector<String> out) throws Exception {
                try {
                    LOG.info("============================row:{}", row);
                    JSONObject rowJson = JSON.parseObject(row);
                    String op = rowJson.getString("op");
                    //history,insert,update
                    if (Arrays.asList("r", "c", "u").contains(op)) {
                        out.collect(rowJson.getJSONObject("after").toJSONString());
                    } else {
                        LOG.info("filter other op:{}", op);
                    }
                } catch (Exception ex) {
                    LOG.warn("filter other format binlog:{}", row);
                }
            }
        });
    }

    /**
     * 过滤数据
     *
     * @param source
     * @param table
     * @return
     */
    private static SingleOutputStreamOperator<String> filterTableData(DataStreamSource<String> source, String table) {
        return source.filter(new FilterFunction<String>() {
            @Override
            public boolean filter(String row) throws Exception {
                try {
                    JSONObject rowJson = JSON.parseObject(row);
                    JSONObject source = rowJson.getJSONObject("source");
                    String tbl = source.getString("table");
                    return table.equals(tbl);
                } catch (Exception ex) {
                    ex.printStackTrace();
                    return false;
                }
            }
        });
    }

    private static List<String> getTableList() {
        List<String> tables = new ArrayList<>();
        String sql = "SELECT TABLE_SCHEMA,TABLE_NAME FROM information_schema.tables WHERE TABLE_SCHEMA = '" + SYNC_DB + "'";
        List<JSONObject> tableList = JdbcUtil.executeQuery(MYSQL_HOST, MYSQL_PORT, MYSQL_USER, MYSQL_PASSWD, sql);
        for (JSONObject jsob : tableList) {
            String schemaName = jsob.getString("TABLE_SCHEMA");
            String tblName = jsob.getString("TABLE_NAME");
            String schemaTbl = schemaName + "." + tblName;
            if (SYNC_TABLES.contains(schemaTbl)) {
                tables.add(tblName);
            }
        }
        return tables;
    }
}

  JdbcUtil.java

import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.*;
import java.util.ArrayList;
import java.util.List;

public class JdbcUtil {

    static {
        try {
//            Class.forName("com.mysql.cj.jdbc.Driver");
            Class.forName("com.mysql.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    private static final Logger LOG = LoggerFactory.getLogger(JdbcUtil.class);

    public static void main(String[] args) throws SQLException {
    }

    public static List<JSONObject> executeQuery(String hostUrl, int port, String user, String password, String sql) {
        List<JSONObject> beJson = new ArrayList<>();
        String connectionUrl = String.format("jdbc:mysql://%s:%s/league_test?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai", hostUrl, port);
        Connection con = null;
        try {
            con = DriverManager.getConnection(connectionUrl, user, password);
            PreparedStatement ps = con.prepareStatement(sql);
            ResultSet rs = ps.executeQuery();
            beJson = resultSetToJson(rs);
        } catch (SQLException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                con.close();
            } catch (Exception e) {
            }
        }
        return beJson;
    }

    private static List<JSONObject> resultSetToJson(ResultSet rs) throws SQLException {
        List<JSONObject> list = new ArrayList<>();
        ResultSetMetaData metaData = rs.getMetaData();
        int columnCount = metaData.getColumnCount();
        while (rs.next()) {
            JSONObject jsonObj = new JSONObject();
            for (int i = 1; i <= columnCount; i++) {
                String columnName = metaData.getColumnLabel(i);
                String value = rs.getString(columnName);
                jsonObj.put(columnName, value);
            }
            list.add(jsonObj);
        }
        return list;
    }
}

  pom.xml:

        <dependency>
            <groupId>com.ververica</groupId>
            <artifactId>flink-connector-mysql-cdc</artifactId>
            <version>2.4.0</version>
        </dependency>
2.1 Mysql 打开 bin-log 功能

  og_bin 的Value如果为ON代表开启,如果为OFF代表关闭,MySQL8.0默认是开启的:

# 查看是否开启binlog
mysql> SHOW VARIABLES LIKE '%log_bin%';

  关闭状态:

在这里插入图片描述

  • log_bin为ON代表MySQL已经开启binlog日志记录
  • log_bin_basename配置了binlog的文件路径及文件前缀名
  • log_bin_index配置了binlog索引文件的路径

  开启状态:

在这里插入图片描述

# 在centos中mysql的配置文件一般都在/etc/mysql目录下,如果不在可以通过 find / -name "my.cnf" 查找
vi /etc/mysql/my.cnf

# 服务ID
server-id=1
# binlog 配置 只要配置了log_bin地址 就会开启
log_bin = /var/lib/mysql/mysql_bin
# 日志存储天数 默认0 永久保存
# 如果数据库会定期归档,建议设置一个存储时间不需要一直存储binlog日志,理论上只需要存储归档之后的日志
expire_logs_days = 30
# binlog最大值
max_binlog_size = 1024M
# 规定binlog的格式,binlog有三种格式statement、row、mixad,默认使用statement,建议使用row格式
binlog_format = ROW
# 在提交n次事务后,进行binlog的落盘,0为不进行强行的刷新操作,而是由文件系统控制刷新日志文件,如果是在线交易和账有关的数据建议设置成1,如果是其他数据可以保持为0即可
sync_binlog = 1

# 重启MySQL服务使配置生效
systemctl restart mysqld / service mysql restart

# 查看日志列表
SHOW MASTER LOGS;

可参考:MySQL 开启配置binlog以及通过binlog恢复数据

2.2 在 Mysql 中建库建表准备
CREATE DATABASE IF NOT EXISTS cloud_test;
CREATE DATABASE IF NOT EXISTS league_test;

CREATE TABLE league_test.oc_settle_profit (
        id                           varchar(32),
        show_profit_id               varchar(32),
        order_no                     varchar(32),
        from_user_id                 varchar(32),
        from_user_type               int(11),
        user_id                      varchar(32),
        user_type                    int(11),
        rate                         int(11),
        amount                       int(11),
        type                         int(11),
        add_time                     datetime,
        state                        int(11),
        expect_profit_time           datetime,
        profit_time                  datetime,
        profit_mode                  int(11),
        opt_code                     varchar(32),
        opt_name                     varchar(32),
        acct_circle                  varchar(32),
        process_state                int(11),
        parent_id                    varchar(32),
        keep_account_from_user_id    varchar(32),
        keep_account_from_bm_user_id varchar(32),
        keep_account_user_id         varchar(32),
        keep_account_bm_user_id      varchar(32),
        biz_type                     int(11),
        remark                       varchar(32),
        contribute_user_id           varchar(32),
        relation_brand_owner_id      varchar(32),
        PRIMARY KEY (id) USING BTREE
);

CREATE TABLE cloud_test.dws_profit_record_hdj_flink_api (
        id                      varchar(32),
        show_profit_id          varchar(32),
        order_no                varchar(32),
        from_user_id            varchar(32),
        from_user_type          int(11),
        user_id                 varchar(32),
        user_type               int(11),
        amount                  int(11),
        profit_time             datetime,
        state                   int(11),
        acct_circle             varchar(32),
        biz_type                int(11),
        contribute_user_id      varchar(32),
        relation_brand_owner_id varchar(32),
        remark                  varchar(32),
        add_time                datetime,
        PRIMARY KEY (id) USING BTREE
        );
2.3 遇到的坑

  用 JDBC 连接 Mysql 的时候报错:The MySQL server has a timezone offset (0 seconds ahead of UTC)

  原因:从错误即可知道是时区的错误。

show variables like '%time_zone%';
Variable_name   |Value |
----------------+------+
time_zone       |SYSTEM|

// 或者下面这条命令
SELECT @@global.time_zone;

  解决:使用 root 用户登录 mysql,再执行 set global time_zone='+8:00' 命令。

  注意:一开始改成了 SET GLOBAL time_zone = 'Asia/Shanghai',但并不好使。

2.4 测试

  Idea 启动程序后,在 oc_settle_profit 表中插入数据后 dws_profit_record_hdj_flink_api 也可以同步插入相应的数据。

参考:
【博学谷学习记录】超强总结,用心分享|大数据之flinkCDC
一次打通FlinkCDC同步Mysql数据

三、番外

  用 Flink CDC 可以监控 Mysql,但无法监控 StarRocks,和官方询问过,目前 StarRocks 并没有像 Mysql 这样被外部感知 DDL 操作的 bin-log 功能,所以暂时还无法用 Flink CDC 监控 StarRocks。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

软件标准研发管理流程文件,项目管理,项目经理管理(word原件)

为了规范系统开发流程&#xff0c;我们制定了详尽的规范文档&#xff0c;旨在通过标准化、系统化的方法提升开发效率与项目质量。该流程从明确需求阶段开始&#xff0c;通过详细的设计规划确保解决方案的可行性与前瞻性&#xff0c;随后进入高效的编码实现阶段&#xff0c;遵循…

AAA 数据库事务隔离级别及死锁

目录 一、事务的四大特性&#xff08;ACID&#xff09; 1. 原子性(atomicity)&#xff1a; 2. 一致性(consistency)&#xff1a; 3. 隔离性(isolation)&#xff1a; 4. 持久性(durability)&#xff1a; 二、死锁的产生及解决方法 三、事务的四种隔离级别 0 .封锁协议 …

固定电话怎么认证显示公司名称?

在当今商业环境中&#xff0c;企业的联系方式&#xff0c;尤其是固定电话&#xff0c;不仅是与客户沟通的重要桥梁&#xff0c;也是展示企业专业形象的一部分。许多企业希望通过拨打固定电话联系客户时&#xff0c;能够对外显示公司名称&#xff0c;以此来增加电话的可信度和品…

使用 MMDetection 实现 Pascal VOC 数据集的目标检测项目练习(二) ubuntu的下载安装

首先&#xff0c;Linux系统是人工智能和深度学习首选系统。原因如下: 开放性和自由度&#xff1a;Linux 是一个开源操作系统&#xff0c;允许开发者自由修改和分发代码。这在开发和研究阶段非常有用&#xff0c;因为开发者可以轻松地访问和修改底层代码。社区支持&#xff1a;…

GetX的一些高级API

目录 前言 一、一些常用的API 二、局部状态组件 1.可选的全局设置和手动配置 2.局部状态组件 1.ValueBuilder 1.特点 2.基本用法 2.ObxValue 1.特点 2.基本用法 前言 这篇文章主要讲解GetX的一些高级API和一些有用的小组件。 一、一些常用的API GetX提供了一些高级…

做一个干电池的电量检测器03:数值拟合与电路仿真

首先在表格中进行详细的计算&#xff0c;整理出所需的数据。接着&#xff0c;我们运用MATLAB的强大功能对这些数据进行插值处理&#xff0c;生成了一个离散的数值数组。这个数组的每个数值都精确地对应着模数转换器&#xff08;ADC&#xff09;采样到的信号。通过这些数值&…

# linux从入门到精通-从基础学起,逐步提升,探索linux奥秘(十九)--mysql数据库基本操作

linux从入门到精通-从基础学起&#xff0c;逐步提升&#xff0c;探索linux奥秘&#xff08;十九&#xff09;–mysql数据库基本操作 一、MySQL的基本操作&#xff08;1&#xff09;&#xff08;难点&#xff09; 1、名词介绍 以Excel文件举例&#xff1a; 数据库&#xff1a…

关于我的编程语言——C/C++——第四篇(深入1)

&#xff08;叠甲&#xff1a;如有侵权请联系&#xff0c;内容都是自己学习的总结&#xff0c;一定不全面&#xff0c;仅当互相交流&#xff08;轻点骂&#xff09;我也只是站在巨人肩膀上的一个小卡拉米&#xff0c;已老实&#xff0c;求放过&#xff09; 字符类型介绍 char…

【python】OpenCV—Tracking(10.4)—Centroid

文章目录 1、任务描述2、人脸检测模型3、完整代码4、结果展示5、涉及到的库函数6、参考 1、任务描述 基于质心实现多目标&#xff08;以人脸为例&#xff09;跟踪 人脸检测采用深度学习的方法 核心步骤&#xff1a; 步骤#1&#xff1a;接受边界框坐标并计算质心 步骤#2&…

Unity核心笔记

1、认识模型的制作 1.建模 2.展UV 3.材质和纹理贴图 4.骨骼绑定 5.动画制作 总结 2、图片导入概述 1.Unity支持的图片格式 2.图片设置的6大部分 3、纹理类型设置 1.纹理类型主要是设置什么 2.参数讲解 4、纹理形状设置 1.纹理形状主要设置什么 2.参数讲解 5、纹理高级设置 …

(57)MATLAB使用迫零均衡器和MMSE均衡器的BPSK调制系统仿真

文章目录 前言一、仿真测试模型二、仿真代码三、仿真结果四、迫零均衡器和MMSE均衡器的实现1.均衡器的MATLAB实现2.均衡器的性能测试 总结 前言 本文给出仿真模型与MATLAB代码&#xff0c;分别使用具有ISI的三个不同传输特性的信道&#xff0c;仿真测试了使用迫零均衡器和MMSE…

[项目] C++基于多设计模式下的同步异步日志系统

[项目] C基于多设计模式下的同步&异步日志系统 文章目录 [项目] C基于多设计模式下的同步&异步日志系统日志系统1、项目介绍2、开发环境3、核心技术4、日志系统介绍4.1 日志系统的价值4.2 日志系统技术实现4.2.1 同步写日志4.2.2 异步写日志 5、相关技术知识5.1 不定参…

动态规划应该如何学习?

动态规划如何学习 参考灵神的视频和题解做的笔记&#xff08;灵神YYDS&#xff0c;以后也都会用这套逻辑去思考&#xff09; 枚举选哪个&#xff1a; 动态规划入门&#xff1a;从记忆化搜索到递推_哔哩哔哩_bilibili 746. 使用最小花费爬楼梯 - 力扣&#xff08;LeetCode&a…

RK3588的QT交叉编译环境搭建

主要参考为RK3568或RK3288开发板创建交叉编译环境{采用amd64的ubuntu系统配置交叉编译arm64开发环境}(保姆级包括安装QT)超详细记录版_rk3568交叉编译-CSDN博客 先说一下&#xff0c;使用的Ubuntu20.04.5版本&#xff0c;qt源码用的5.14.2版本&#xff0c;交叉编译器使用RK3588…

专利生成穿刺demo

一、做原型 做原型&#xff1f;具体需求是啥&#xff1f;只有一个“帮助客户生成专利说明书”这样一个笼统的要求&#xff1f; 只有这些肯定是不能用来指导原型开发的。既然目前没有准确的需求&#xff0c;那就先看看现有的产品现状吧。 1.竞品分析 怎么开展哪&#xff1f;…

数字信号处理Python示例(3)生成三相正弦信号

文章目录 前言一、三相正弦信号的表示二、生成三相正弦信号的Python代码三、三相正弦信号的图示与分析四、生成幅度不相等的三相正弦信号的Python代码五、幅度不相等的三相正弦信号的图示与分析写在后面的话 前言 首先给出三相正弦信号的数学表达式&#xff0c;并给出生成三相…

【linux 多进程并发】0302 Linux下多进程模型的网络服务器架构设计,实时响应多客户端请求

0302 多进程网络服务器架构 ​专栏内容&#xff1a; postgresql使用入门基础手写数据库toadb并发编程 个人主页&#xff1a;我的主页 管理社区&#xff1a;开源数据库 座右铭&#xff1a;天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物. 一、概…

Linux云计算 |【第五阶段】CLOUD-DAY9

主要内容&#xff1a; Metrics资源利用率监控、存储卷管理&#xff08;临时卷ConfitMap、EmptyDir、持久卷HostPath、NFS(PV/PVC)&#xff09; 一、Metrics介绍 metrics是一个监控系统资源使用的插件&#xff0c;可以监控Node节点上的CPU、内存的使用率&#xff0c;或Pod对资…

Kafka 判断一个节点是否还活着有那两个条件?

大家好&#xff0c;我是锋哥。今天分享关于【Kafka 判断一个节点是否还活着有那两个条件&#xff1f;】面试题&#xff1f;希望对大家有帮助&#xff1b; Kafka 判断一个节点是否还活着有那两个条件&#xff1f; 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 在Ka…

PyQt5实战——多脚本集合包,UI以及工程布局(二)

个人博客&#xff1a;苏三有春的博客 系列往期&#xff1a; PyQt5实战——多脚本集合包&#xff0c;前言与环境配置&#xff08;一&#xff09; 布局 2.1 UI页面布局 整体框架分为分为三个部分&#xff0c;垂直分布。 第一个部分为功能选择按钮&#xff08;如UTF-8转换&#…