ClickHouse 数据保护指南:从备份到迁移的全流程攻略

news2024/10/12 6:19:18

一、背景

  • 运行3年的clickhouse需要迁移机房,迁移单库单表的140亿条的数据。
  • 采用clickhouse-backup 的方式进行备份迁移,打包备份,再加上数据拷贝,数据恢复 一共花费30分钟。
  • 数据在一定量级,避免使用SQL 导入导出的方式,效率太低

image-20241010191118098

image-20241010191124552

二、clickhouse-backup工具介绍

image-20241010153103227

clickhouse-backup 是社区开源的一个 ClickHouse 备份工具,可用于实现数据迁移。其原理是先创建一个备份,然后从备份导入数据,类似 MySQL 的 mysqldump + SOURCE。这个工具可以作为常规的异地冷备方案。

  • clickhouse-backup社区地址: https://github.com/Altinity/clickhouse-backup

2.1、工作原理

clickhouse-backup 的备份原理主要依赖于 ClickHouse 数据库的存储结构和操作流程,结合增量备份和文件系统操作来实现高效的备份。其核心思想是通过对数据库表的数据和元数据进行快照,保存这些信息到指定的存储位置,并确保在备份过程中数据的一致性。

2.1.1、ClickHouse 数据存储结构

ClickHouse 将数据存储在表的分区中,每个分区包含多个数据块文件,这些文件存储在 ClickHouse 服务器的本地文件系统中。ClickHouse 使用的存储引擎(如 MergeTree)通过这些文件来管理数据,因此备份过程实际上就是将这些文件(表数据和元数据)复制到备份存储中。

2.1.2 、备份操作步骤

  • 数据冻结(freeze)

在进行备份时,clickhouse-backup 会使用 ALTER TABLE ... FREEZE 命令将数据分区冻结。冻结操作会创建数据的一个一致性快照,确保数据在备份过程中不受写入操作的影响。这个快照是通过将分区中的数据硬链接(hard link)到特殊的备份目录中来实现的。由于是硬链接,创建快照不会占用额外的磁盘空间,并且操作非常快速。

  • 备份数据的复制

冻结后的数据文件被复制到备份目录中。clickhouse-backup 会将这些文件以及相关的元数据(如表结构)保存到指定的存储后端(本地存储、S3 兼容存储或云存储等)。在这个过程中,备份的文件包括:表结构(schema):包含创建表的 SQL 语句及相关信息。数据文件:包含实际的分区和数据块。

  • 增量备份

对于增量备份,clickhouse-backup 仅备份自上次备份以来新增或修改的数据分区。这是通过比较文件的哈希值或时间戳来确定哪些分区已发生变化的,从而避免重复备份未改变的数据块。这一机制大幅减少了备份的数据量和所需时间。

2.1.3、 数据恢复原理

在恢复时,clickhouse-backup 根据备份中的表结构信息重新创建表,并将数据文件复制回 ClickHouse 的数据目录。恢复过程可以是全量恢复或增量恢复:

  • 全量恢复:从全量备份中恢复所有数据。

  • 增量恢复:先恢复全量备份,再应用增量备份中的数据。

恢复操作确保恢复的数据与备份时的数据完全一致。

2.1.4、一致性保障

ClickHouse 的 FREEZE 命令确保在备份期间即使有写入操作,已冻结的数据文件也不会被修改。备份过程使用文件系统的硬链接特性,在不复制文件数据的情况下创建一致性的快照,因此备份时的数据保持不变。

2.1.5、备份存储位置

clickhouse-backup 可以将备份存储在多种存储后端,包括:

  • 本地文件系统:将备份保存到本地目录。
  • S3 兼容存储:如 Amazon S3、MinIO 等,使用对象存储来保存备份。
  • Google Cloud Storage:将备份上传到云端存储。

三、环境信息

  • 本文不去复现140亿数据怎么迁移,通过演示部署一台clickhouse ,去使用官方的demo 数据演示如何备份,迁移;只要使用对了方法,后面任何迁移都不用担心
软件名称版本备注
openeuler22.03 LTS SP4
clickhouse-backup2.2.5docker部署
clickhouse24.5.1docker部署

四、部署clickhouse

**为了快速验证环境,本文采用docker-compose部署方式 **

  • 代码库地址,提供Dockerfile 文件: https://cnb.cool/srebro/clickhouse
  • 镜像地址:docker.cnb.cool/srebro/clickhouse:24.5.1
  • 指定了docker网络,需要提前创建好docker 网络,docker network create -d bridge --subnet "10.22.33.0/24" --gateway "10.22.33.1" srebro
1、创建目录
mkdir -p /home/application/Database/clickhouse/{data,log}

2、创建docker-compose.yaml 文件,见 docker-compose.yaml 文件
vim /home/application/Middleware/kafka/docker-compose.yml

services:
  clickhouse:
    image: docker.cnb.cool/srebro/clickhouse:24.5.1
    container_name: clickhouse
    restart: always
    environment:
      CLICKHOUSE_USER: 'default'
      CLICKHOUSE_PASSWORD: 'srebro@2024' ##这里自定义clickhouse数据库密码
      CLICKHOUSE_DEFAULT_ACCESS_MANAGEMENT: '1'
    networks:
      - srebro
    ports:
      - "8123:8123"
      - "9000:9000"
    volumes:
      - /home/application/Database/clickhouse/log:/var/log/clickhouse-server
      - /home/application/Database/clickhouse/data:/var/lib/clickhouse

networks:
  srebro:
    external: true


3、运行docker-compose创建容器
docker-compose up -d

五、导入官方演示数据,并验证

  • 演示官方数据:【纽约公共图书馆“菜单上有什么?”数据集】 https://clickhouse.com/docs/zh/getting-started/example-datasets/menus

5.1 下载官方数据

# 创建工作目录,下载数据集
$ mkdir -p /home/application/Database/clickhouse/data/clickhouse-demo
$ cd  /home/application/Database/clickhouse/data/clickhouse-demo
$ wget https://s3.amazonaws.com/menusdata.nypl.org/gzips/2021_08_01_07_01_17_data.tgz

# 解压数据集
# 解压后的的大小约为 150 MB
$ tar xvf 2021_08_01_07_01_17_data.tgz

数据集由四个表组成:

  • Menu - 有关菜单的信息,其中包含:餐厅名称,看到菜单的日期等
  • Dish - 有关菜肴的信息,其中包含:菜肴名称以及一些特征。
  • MenuPage - 有关菜单中页面的信息,每个页面都属于某个 Menu
  • MenuItem - 菜单项。某个菜单页面上的菜肴及其价格:指向 DishMenuPage的链接。

5.2 进入到容器中

# 进入到容器
$ docker exec -it clickhouse bash

#登录数据库
$ clickhouse-client
ClickHouse client version 24.5.1.1763 (official build).
Connecting to localhost:9000 as user default.
Connected to ClickHouse server version 24.5.1.

Warnings:
 * Linux transparent hugepages are set to "always". Check /sys/kernel/mm/transparent_hugepage/enabled

998ed9141382 :) 


5.3 创建数据库

# 创建数据库
998ed9141382 :)  create database demo;

5.4 创建表

# 进入数据库,创建表
998ed9141382 :)  use demo;

#分开单独创建每一个表
CREATE TABLE dish
(
    id UInt32,
    name String,
    description String,
    menus_appeared UInt32,
    times_appeared Int32,
    first_appeared UInt16,
    last_appeared UInt16,
    lowest_price Decimal64(3),
    highest_price Decimal64(3)
) ENGINE = MergeTree ORDER BY id;



CREATE TABLE menu
(
    id UInt32,
    name String,
    sponsor String,
    event String,
    venue String,
    place String,
    physical_description String,
    occasion String,
    notes String,
    call_number String,
    keywords String,
    language String,
    date String,
    location String,
    location_type String,
    currency String,
    currency_symbol String,
    status String,
    page_count UInt16,
    dish_count UInt16
) ENGINE = MergeTree ORDER BY id;




CREATE TABLE menu_page
(
    id UInt32,
    menu_id UInt32,
    page_number UInt16,
    image_id String,
    full_height UInt16,
    full_width UInt16,
    uuid UUID
) ENGINE = MergeTree ORDER BY id;



CREATE TABLE menu_item
(
    id UInt32,
    menu_page_id UInt32,
    price Decimal64(3),
    high_price Decimal64(3),
    dish_id UInt32,
    created_at DateTime,
    updated_at DateTime,
    xpos Float64,
    ypos Float64
) ENGINE = MergeTree ORDER BY id;

5.4 导入数据

$ cd /var/lib/clickhouse/clickhouse-demo

$ clickhouse-client --format_csv_allow_single_quotes 0 --input_format_null_as_default 0 --query "INSERT INTO demo.dish FORMAT CSVWithNames" < Dish.csv

$ clickhouse-client --format_csv_allow_single_quotes 0 --input_format_null_as_default 0 --query "INSERT INTO demo.menu FORMAT CSVWithNames" < Menu.csv

$ clickhouse-client --format_csv_allow_single_quotes 0 --input_format_null_as_default 0 --query "INSERT INTO demo.menu_page FORMAT CSVWithNames" < MenuPage.csv


$ clickhouse-client --format_csv_allow_single_quotes 0 --input_format_null_as_default 0 --date_time_input_format best_effort --query "INSERT INTO demo.menu_item FORMAT CSVWithNames" < MenuItem.csv

我们将再创建一个表“menu_item_denorm”,其中将包含所有联接在一起的数据:

#登录数据库
$ clickhouse-client

# 进入数据库,创建表
998ed9141382 :)  use demo;

#创建表

CREATE TABLE menu_item_denorm
ENGINE = MergeTree ORDER BY (dish_name, created_at)
AS SELECT
    price,
    high_price,
    created_at,
    updated_at,
    xpos,
    ypos,
    dish.id AS dish_id,
    dish.name AS dish_name,
    dish.description AS dish_description,
    dish.menus_appeared AS dish_menus_appeared,
    dish.times_appeared AS dish_times_appeared,
    dish.first_appeared AS dish_first_appeared,
    dish.last_appeared AS dish_last_appeared,
    dish.lowest_price AS dish_lowest_price,
    dish.highest_price AS dish_highest_price,
    menu.id AS menu_id,
    menu.name AS menu_name,
    menu.sponsor AS menu_sponsor,
    menu.event AS menu_event,
    menu.venue AS menu_venue,
    menu.place AS menu_place,
    menu.physical_description AS menu_physical_description,
    menu.occasion AS menu_occasion,
    menu.notes AS menu_notes,
    menu.call_number AS menu_call_number,
    menu.keywords AS menu_keywords,
    menu.language AS menu_language,
    menu.date AS menu_date,
    menu.location AS menu_location,
    menu.location_type AS menu_location_type,
    menu.currency AS menu_currency,
    menu.currency_symbol AS menu_currency_symbol,
    menu.status AS menu_status,
    menu.page_count AS menu_page_count,
    menu.dish_count AS menu_dish_count
FROM menu_item
    JOIN dish ON menu_item.dish_id = dish.id
    JOIN menu_page ON menu_item.menu_page_id = menu_page.id
    JOIN menu ON menu_page.menu_id = menu.id;

5.5 验证数据

# 查看表数据
SELECT count() FROM menu_item_denorm;

image-20241010215040282

#菜品的平均历史价格
SELECT
    round(toUInt32OrZero(extract(menu_date, '^\\d{4}')), -1) AS d,
    count(),
    round(avg(price), 2),
    bar(avg(price), 0, 100, 100)
FROM menu_item_denorm
WHERE (menu_currency = 'Dollars') AND (d > 0) AND (d < 2022)
GROUP BY d
ORDER BY d ASC;

image-20241010215129714

六、使用clickhouse-backup 工具

image-20241010215613280

  • clickhouse-backup 工具可采用docker 的部署方式,需要把clickhouse 的数据目录挂在到clickhouse-backup 容器中
  • 需要在env 中指定CLICKHOUSE_PASSWORD,CLICKHOUSE_HOST,CLICKHOUSE_PORT 变量,具体的变量名称,可以见官方的https://github.com/Altinity/clickhouse-backup#explain-config-parameters

6.1 运行clickhouse-backup容器

⚠️ 这里我定义的clickhouse的数据目录在宿主机上的/home/application/Database/clickhouse 目录下,需要把这个目录也挂载到clickhouse-backup容器 中

$ docker run --rm -it --network host -v "/home/application/Database/clickhouse/data:/var/lib/clickhouse"    -e CLICKHOUSE_PASSWORD="srebro@2024"    -e CLICKHOUSE_HOST="localhost"    -e CLICKHOUSE_PORT="9000"    altinity/clickhouse-backup:2.2.5 bash

bash-5.1# 

6.2 clickhouse-backup 相关命令

6.2.1 查看默认的配置项

$ clickhouse-backup default-config

image-20241010220430055

6.2.2 查看可备份的表

【默认的配置文件中已经过滤掉system和default 库下面的所有表】

$ clickhouse-backup tables

image-20241010220740428

6.2.3 全库备份

$ clickhouse-backup create

image-20241010221015373

  • 备份存储在中 $data_path/backup 下,即/var/lib/clickhouse/backup 下; 备份名称默认为时间戳
$ ls -l /var/lib/clickhouse/backup

image-20241010221150450

  • 也可手动指定备份名称,如 srebro-10-10
$ clickhouse-backup create  srebro-10-10

$ ls -l /var/lib/clickhouse/backup

image-20241010221408656

  • 备份包含两个目录:

    • metadata目录: 包含重新创建所需的DDL SQL
    • shadow目录: 包含作为ALTER TABLE … FREEZE操作结果的数据
    $ ls -l /var/lib/clickhouse/backup/srebro-10-10/
    

    image-20241010221554179

6.2.4 单表备份

#备份单表
$ clickhouse-backup create  -t demo.dish

#备份多个表
$ clickhouse-backup create  -t demo.dish,demo.menu

image-20241010221907547

6.2.5 查看备份记录

$ clickhouse-backup list

image-20241010222018292

6.2.6 删除备份文件

$ clickhouse-backup delete local srebro-10-10

#再次查看备份记录,发现没有srebro-10-10
$ clickhouse-backup list

image-20241010222144194

6.2.7 数据恢复

$ clickhouse-backup restore --help

NAME:
   clickhouse-backup restore - Create schema and restore data from backup
USAGE:
   clickhouse-backup restore  [-t, --tables=<db>.<table>] [-s, --schema] [-d, --data] [--rm, --drop] <backup_name>
OPTIONS:
   --config FILE, -c FILE                   Config FILE name. (default: "/etc/clickhouse-backup/config.yml") [$CLICKHOUSE_BACKUP_CONFIG]
   --table value, --tables value, -t value  
   --schema, -s                             Restore schema only
   --data, -d                               Restore data only
   --rm, --drop                             Drop table before restore

参数:
--table   只恢复特定表,可使用正则。如针对特定的数据库:--table=dbname.*
--schema  只还原表结构, 简写 -s
--data    只还原数据, 简写 -d
--rm      数据恢复之前,先删除需要恢复的表

七、使用clickhouse-backup备份与恢复数据-场景实战

  • 备份前,先查看demo.menu_item_denorm 表里的数据量,一共是1329175条数据
SELECT count() FROM demo.menu_item_denorm;

image-20241010222636663

  • 查看可备份的表
clickhouse-backup tables

image-20241010222816716

  • 全库备份数据
$ clickhouse-backup create

image-20241010224031695

  • 查看备份文件是否存在
$ clickhouse-backup list

image-20241010224140418

  • 模拟删除demo数据库
$ clickhouse-client

998ed9141382 :) drop database demo;
998ed9141382 :) show databases;

image-20241010224301603

  • 使用备份文件恢复数据库
$ clickhouse-backup restore 2024-10-10T14-40-20 -s -d --rm

image-20241010224652237

PS: 如果遇到,下面的情况:

2024/10/10 14:46:13.769364 error can't create table `demo`.`menu_page`: code: 57, message: Directory for table data store/738/738c9b6f-354b-41d9-ad2a-c9cc27142853/ already exists after 5 times, please check your schema dependencies

解决方法: 重启clickhouse 数据库即可

  • 验证数据是否完整
SELECT count() FROM demo.menu_item_denorm;

image-20241010224908937

发现数据和删除前数量是一致的,我们使用clickhouse-backup 恢复成功

八、使用脚本定期异机远程备份

**环境: **

  • clickhouse 数据库 192.168.99.102
  • 备份存储服务器 192.168.99.101
  • 使用二进制方式,部署的clickhouse-backup 工具

**条件: **

  • 备份存储服务器 建立备份目录,/data/clickhouse-back
  • clickhouse 数据库 可以免密到 存储服务器 上,免密传输备份文件
  • 需要创建,/etc/clickhouse-backup/config.yml 配置文件,指定 clickhouse的数据目录,数据库密码,监控地址,端口,以及本地备份保存策略
vim  /var/lib/clickhouse/clickhouse-backup.sh


#!/bin/bash
#Author        srebro.cn
####################################################
##
##      clickhouse-back script
##      backup data at remote host
##      you should config ssh trust
##
####################################################
MSNAME=srebro
BAKFILE=$MSNAME-`date +%Y%m%d%H%M%S`
LOCAL_BAKDIR=/var/lib/clickhouse/backup
REMOTE_BAKDIR=/data/clickhouse-back
REMOTE_HOST=root@192.168.99.101
#备份到本地
/usr/bin/clickhouse-backup create $BAKFILE
if [[ $? != 0 ]]; then
    echo "clickhouse-backup Create FAILED" > /var/log/clickhouse-backup.log
    exit
else

#SCP备份到远程主机
scp -rp $LOCAL_BAKDIR/$BAKFILE $REMOTE_HOST:$REMOTE_BAKDIR/
    if [[ $? != 0 ]]; then
        echo "clickhouse-backup FAILED" > /var/log/clickhouse-backup.log
    else
        echo "clickhouse-backup successful" > /var/log/clickhouse-backup.log
    fi
fi
 
#本地保留的时间,可以再配置文件中定义,如 backups_to_keep_local: 7,就表示本地保留7天备份数据; 
#可以见官方的https://github.com/Altinity/clickhouse-backup#explain-config-parameters 中定义的参数

#定期删除远程备份文件
ssh $REMOTE_HOST  "find $REMOTE_BAKDIR/srebro* -maxdepth 0 -mtime +30 -type d | xargs rm -rf {}"

九、常见问题

9.1 问题现象:使用clickhouse-backup 恢复数据时,提示UUID 问题

clickhouse-backup restore 2021-08-21T06-35-10 -s -d --rm
2021/08/21 14:40:51 error can't create table `default`.`t`: code: 57, message: 
Directory for table data store/c57/c5780d8a-7d5a-47a3-8578-0d8a7d5a37a3/ already exists after 1 times, please check your schema depencncies



解决方法:

去掉 备份文件中  ${backup_path}/2021-08-21T06-35-10/metadata/default/t.json 中的UUID
UUID '80ea6411-9c37-4d47-80ea-64119c374d47'
再次执行恢复
clickhouse-backup restore 2021-08-21T06-35-10 -s -d --rm
SELECT count(1)
FROM datasets.hits_v1
┌─count(1)─┐
│ 17747796 │
└──────────┘
1 rows in set. Elapsed: 0.016 sec. 
localhost :) exit

9.2 问题现象:使用clickhouse-backup 恢复数据时,提示 message: Directory for table data store already exists 问题

2024/10/10 14:46:13.769364 error can't create table `demo`.`menu_page`: code: 57, message: Directory for table data store/738/738c9b6f-354b-41d9-ad2a-c9cc27142853/ already exists after 5 times, please check your schema dependencies


解决方法: 

重启clickhouse 数据库即可

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

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

相关文章

配置 Visual studio 2022 Connector C++ 8.0环境 连接MySQL

Connector C 8.0 环境配置 1. 配置 Connector C 头文件地址 &#xff08;1&#xff09; 在Mysql的安装路径中找到 MySQL\Connector C 8.0\include\jdbc 例如 &#xff1a; C:\Program Files\MySQL\Connector C 8.0\include\jdbc &#xff08;2&#xff09; 打开VS2022&…

如何用好 CloudFlare 的速率限制防御攻击

最近也不知道咋回事儿,群里好多站长都反映被CC 攻击了。有人说依旧是 PCDN 干的,但明月感觉不像,因为有几个站长被 CC 攻击都是各种动态请求(这里的动态请求指的是.php 文件的请求)。经常被攻击的站长们都知道,WordPress /Typecho 这类动态博客系统最怕的就是这种动态请求…

塔吊识别数据集 yolo格式 共5076张图片 已划分好训练验证 txt格式 yolo可直接使用

塔吊识别数据集 yolo格式 共5076张图片 已划分好训练验证 txt格式 yolo可直接使用。 类别&#xff1a;塔吊(Tower-crane) 一种 训练数据已划分&#xff0c;配置文件稍做路径改动即可训练。 训练集&#xff1a; 4724 &#xff08;正面3224 负面1500&#xff09; 验证集&#xf…

【父子线程传值TransmittableThreadLocal使用踩坑-及相关知识拓展】

文章目录 一.业务背景二.TransmittableThreadLocal是什么&#xff1f;三.问题复现1.定义注解DigitalAngel2.定义切面3.TransmittableThreadLocal相关4.线程池配置信息5.Controller6.Service7.测试结果8.问题分析9 解决办法及代码改造10.最终测试&#xff1a; 四.与 ThreadLocal…

【大模型实战篇】创建有效的大模型提示词Prompt(提示词工程)

1. 背景介绍 随着chatgpt、llama、chatglm、claude AI等一系列生成式 AI 工具的普及&#xff0c;很明显能感受到&#xff0c;个人的生产力得到了大幅地提升。这些生成式算法模型能够帮助我们开发新想法、轻松获取信息&#xff0c;并简化各种个人和职业任务。个人在日常生活、工…

问卷调查毕设计算机毕业设计投票系统SpringBootSSM框架

目录 一、引言‌ ‌二、需求分析‌ 用户角色‌&#xff1a; ‌功能需求‌&#xff1a; ‌非功能需求‌&#xff1a; ‌三、系统设计‌ ‌技术选型‌&#xff1a; ‌数据库设计‌&#xff1a; ‌界面设计‌&#xff1a; ‌四、实现步骤‌ ‌后端实现‌&#xff1a; …

Python快速编程小案例——猜数字

提示&#xff1a;&#xff08;个人学习&#xff09;&#xff0c;案例来自工业和信息化“十三五”人才培养规划教材&#xff0c;《Python快速编程入门》第2版&#xff0c;黑马程序员◎编著 猜数游戏是一种经典的密码破译类益智游戏&#xff0c;通常由两个人参与。一个人在心中设…

【C++网络编程】(三)多线程TCP服务端程序

文章目录 &#xff08;三&#xff09;多线程TCP服务端程序多线程服务端客户端 &#xff08;三&#xff09;多线程TCP服务端程序 图片来源&#xff1a;https://subingwen.cn/linux/concurrence 主线程负责监听和连接多个客户端&#xff0c;子线程负责和对应的客户端进行通信&am…

vue后台管理系统从0到1搭建(4)各组件的搭建

文章目录 vue后台管理系统从0到1搭建&#xff08;4&#xff09;各组件的搭建Main.vue 组件的初构 vue后台管理系统从0到1搭建&#xff08;4&#xff09;各组件的搭建 Main.vue 组件的初构 根据我们的效果来看&#xff0c;分析一下&#xff0c;我们把左边的区域分为一个组件&am…

如何将本地磁盘镜像包部署到docker中(以mysql5_7.tar.gz为例)

1.复制文件到宿主机 2.找到对应目录&#xff0c;docker load docker images就可以看到该镜像啦

PE结构之导入表

流程图: 文件中\样式 加载到进程中时 加载到进程中时的过程,一张图不够放 续图 整个流程 考虑到 PE32 可执行文件&#xff08;64 位&#xff09;&#xff0c;每个 ILT (导入名称表) 条目总结为&#xff1a; 如果设置了高位&#xff08;位 63&#xff0c;也称为“序号标志”&…

【Spring详解】Maven从安装到应用(Maven Help插件的安装)-国内源的配置(中央仓库及私服的概念)

&#x1f308;个人主页&#xff1a;努力学编程’ ⛅个人推荐&#xff1a; c语言从初阶到进阶 JavaEE详解 数据结构 ⚡学好数据结构&#xff0c;刷题刻不容缓&#xff1a;点击一起刷题 &#x1f319;心灵鸡汤&#xff1a;总有人要赢&#xff0c;为什么不能是我呢 &#x1f42f…

48 C 语言实战项目——客户信息管理系统

目录 1 需求说明 1.1 主菜单 1.2 添加客户 1.3 显示客户列表 1.4 修改客户 1.5 删除客户 1.6 退出 2 流程分析 2.1 总流程图 2.2 添加客户流程图 2.3 显示客户列表流程图 2.4 改客户流程图 2.4.1 修改客户总体流程图 2.4.2 具体执行修改部分的流程图 2.5 删除客…

MySQL-约束Constraint详解

文章目录 约束简介非空约束检查约束唯一约束列级约束与表级约束给约束起名字主键约束 约束简介 约束是我们在创建表的时候, 我们可以给表中的字段添加约束确保我们的数据的完整性和有效性, 比如大家平时上网时注册用户常见的 : 用户名不能为空, 对不起, 用户名已经存在等提示信…

【C++】用红黑树模拟实现set与map

目录 一、红黑树的完善&#xff1a; 1、红黑树节点模版的修改&#xff1a; 2、仿函数在模拟实现中的应用&#xff1a; 3、新增迭代器&#xff1a; 4、红黑树中的迭代器实现&#xff1a; 二、set与map的模拟实现&#xff1a; 1、insert&#xff1a; 2、map的[ ]: 三、测…

无刷直流电机工作原理:【图文讲解】

电动机 (俗称马达) 是机械能与电能之间转换装置的通称。可以分为电动机和发电机.一般称电机时就是指电动机。这个在日常应用中&#xff0c;比较多见&#xff0c;比如机器人&#xff0c;手机&#xff0c;电动车等。 直流电机&#xff1a;分为有刷直流电机&#xff08;BDC&#…

本地ubuntu主机搭建我的世界服务器并免费开启公网映射 结合MESM面板 chmlfrp 保姆级教学

本地ubuntu主机搭建我的世界forge服务器并免费开启公网映射 结合MESM面板 chmlfrp 这是一篇很完成的从ssh命令->配置java环境->安装MCS->部署服务器->开启公网映射的我的世界保姆级开服教程,可以慢慢食用ଘ(੭ˊ꒳ˋ)੭ 。 为什么选择forge服务器进行开服&#x…

【前车之鉴】坑啊~ RestHighLevelClient 超时时间偶尔失效问题解决方案

文章目录 show me code缘起原因分析 几点建议 结论&#xff1a;实际你的配置是生效的&#xff0c;只不过效果不明显而已&#xff0c;通过下面的配置放大直观效果。 show me code 核心代码 public static void main(String[] args) {RestClientBuilder builder RestClient.bu…

【M2TR】M2TR: Multi-modal Multi-scale Transformers for Deepfake Detection

文章目录 M2TR: Multi-modal Multi-scale Transformers for Deepfake Detectionkey points研究贡献方法多尺度变压器频率过滤器跨模态融合损失函数SR-DF数据集实验总结M2TR: Multi-modal Multi-scale Transformers for Deepfake Detection 会议/期刊:ICMR ’22 作者: key …

深入理解栈(Stack)(纯小白进)

目录&#xff1a; 一、栈是什么&#xff1f;1. 栈的概念2.栈的结构选择 二、栈的实现1. 栈结构体的定义2. 栈的初始化3. 栈的销毁4. 入栈5.出栈6. 取栈顶元素7. 栈中元素的个数8. 判断栈是否为空 总结 一、栈是什么&#xff1f; 1. 栈的概念 栈&#xff08;Stack&#xff09;…