Files
ccdi/docs/plans/2026-02-28-database-migration.md

29 KiB
Raw Permalink Blame History

数据库迁移实施计划

For Claude: REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.

Goal: 创建自动化脚本完成 CCDI 数据库的完整导出和导入,包括表结构和数据,确保字符集正确无乱码

Architecture: 使用 mysqldump 命令导出数据库,分离表结构和数据为两个 SQL 文件,通过 Bash 脚本自动化管理导出和导入流程,配置文件管理多环境数据库连接信息

Tech Stack: Bash 脚本、mysqldump/mysql 命令行工具、UTF-8/utf8mb4 字符集


Task 1: 创建配置文件模板和安全措施

Files:

  • Create: db_config.conf.template
  • Modify: .gitignore

Step 1: 创建配置文件模板

创建 db_config.conf.template 文件:

# 数据库迁移配置文件模板
# 使用方法:复制此文件为 db_config.conf 并填写实际值

# 源数据库配置(开发环境)
SOURCE_DB_HOST=116.62.17.81
SOURCE_DB_PORT=3306
SOURCE_DB_USER=root
SOURCE_DB_PASS=Kfcx@1234
SOURCE_DB_NAME=ccdi

# 生产环境数据库配置
PROD_DB_HOST=your_production_host
PROD_DB_PORT=3306
PROD_DB_USER=your_production_user
PROD_DB_PASS=your_production_password
PROD_DB_NAME=ccdi

# 测试环境数据库配置(可选)
TEST_DB_HOST=your_test_host
TEST_DB_PORT=3306
TEST_DB_USER=your_test_user
TEST_DB_PASS=your_test_password
TEST_DB_NAME=ccdi

# 导出文件配置
BACKUP_DIR=doc/database/backup
STRUCTURE_FILE=ccdi_structure.sql
DATA_FILE=ccdi_data.sql

# mysqldump 参数配置
CHARACTER_SET=utf8mb4
MAX_ALLOWED_PACKET=512M

Step 2: 更新 .gitignore 文件

.gitignore 文件末尾添加:

# 数据库配置文件(包含敏感信息)
db_config.conf

Step 3: 提交配置模板

git add db_config.conf.template .gitignore
git commit -m "feat: 添加数据库迁移配置模板和安全措施"

Task 2: 创建备份目录结构

Files:

  • Create: doc/database/backup/.gitkeep

Step 1: 创建备份目录

mkdir -p doc/database/backup

Step 2: 创建 .gitkeep 文件保持目录

touch doc/database/backup/.gitkeep

Step 3: 提交目录结构

git add doc/database/backup/.gitkeep
git commit -m "feat: 创建数据库备份目录结构"

Task 3: 创建自动化导出脚本(框架和导出功能)

Files:

  • Create: export_database.sh

Step 1: 创建脚本文件并添加基本框架

创建 export_database.sh 文件:

#!/bin/bash

# CCDI 数据库迁移自动化脚本
# 功能:数据库导出和导入自动化

set -e  # 遇到错误立即退出

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color

# 日志函数
log_info() {
    echo -e "${GREEN}[INFO]${NC} $1"
}

log_warn() {
    echo -e "${YELLOW}[WARN]${NC} $1"
}

log_error() {
    echo -e "${RED}[ERROR]${NC} $1"
}

# 脚本目录
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
CONFIG_FILE="${SCRIPT_DIR}/db_config.conf"

# 检查配置文件
check_config() {
    if [ ! -f "$CONFIG_FILE" ]; then
        log_error "配置文件不存在: $CONFIG_FILE"
        log_info "请先复制配置模板: cp db_config.conf.template db_config.conf"
        log_info "然后编辑 db_config.conf 填写实际数据库连接信息"
        exit 1
    fi

    # 加载配置文件
    source "$CONFIG_FILE"
    log_info "配置文件加载成功"
}

# 检查 mysqldump 命令
check_mysqldump() {
    if ! command -v mysqldump &> /dev/null; then
        log_error "mysqldump 命令未找到"
        log_info "请安装 MySQL 客户端工具"
        exit 1
    fi
    log_info "mysqldump 命令检查通过"
}

# 创建备份目录
create_backup_dir() {
    if [ ! -d "$BACKUP_DIR" ]; then
        mkdir -p "$BACKUP_DIR"
        log_info "创建备份目录: $BACKUP_DIR"
    fi
}

# 导出表结构
export_structure() {
    log_info "开始导出表结构..."

    local output_file="${BACKUP_DIR}/${STRUCTURE_FILE}"

    # 创建临时文件
    local temp_file=$(mktemp)

    # 导出表结构到临时文件
    mysqldump -h "$SOURCE_DB_HOST" \
        -P "$SOURCE_DB_PORT" \
        -u "$SOURCE_DB_USER" \
        -p"$SOURCE_DB_PASS" \
        --no-data \
        --skip-triggers \
        --skip-add-drop-table \
        --default-character-set=$CHARACTER_SET \
        --single-transaction \
        --max_allowed_packet=$MAX_ALLOWED_PACKET \
        "$SOURCE_DB_NAME" > "$temp_file" 2>/dev/null

    if [ $? -eq 0 ]; then
        # 添加字符集声明到文件头部
        {
            echo "-- CCDI 数据库表结构"
            echo "-- 导出时间: $(date '+%Y-%m-%d %H:%M:%S')"
            echo "-- 源数据库: ${SOURCE_DB_HOST}:${SOURCE_DB_PORT}/${SOURCE_DB_NAME}"
            echo "-- 字符集: ${CHARACTER_SET}"
            echo ""
            echo "SET NAMES utf8mb4;"
            echo "SET CHARACTER SET utf8mb4;"
            echo "SET GLOBAL character_set_client=utf8mb4;"
            echo "SET GLOBAL character_set_connection=utf8mb4;"
            echo "SET GLOBAL character_set_results=utf8mb4;"
            echo ""
            cat "$temp_file"
        } > "$output_file"

        rm -f "$temp_file"
        log_info "表结构导出成功: $output_file"
        log_info "文件大小: $(du -h "$output_file" | cut -f1)"
    else
        rm -f "$temp_file"
        log_error "表结构导出失败"
        exit 1
    fi
}

# 导出数据
export_data() {
    log_info "开始导出数据..."

    local output_file="${BACKUP_DIR}/${DATA_FILE}"

    # 创建临时文件
    local temp_file=$(mktemp)

    # 导出数据到临时文件
    mysqldump -h "$SOURCE_DB_HOST" \
        -P "$SOURCE_DB_PORT" \
        -u "$SOURCE_DB_USER" \
        -p"$SOURCE_DB_PASS" \
        --no-create-info \
        --skip-triggers \
        --default-character-set=$CHARACTER_SET \
        --single-transaction \
        --complete-insert \
        --extended-insert \
        --max_allowed_packet=$MAX_ALLOWED_PACKET \
        "$SOURCE_DB_NAME" > "$temp_file" 2>/dev/null

    if [ $? -eq 0 ]; then
        # 添加字符集声明到文件头部
        {
            echo "-- CCDI 数据库数据"
            echo "-- 导出时间: $(date '+%Y-%m-%d %H:%M:%S')"
            echo "-- 源数据库: ${SOURCE_DB_HOST}:${SOURCE_DB_PORT}/${SOURCE_DB_NAME}"
            echo "-- 字符集: ${CHARACTER_SET}"
            echo ""
            echo "SET NAMES utf8mb4;"
            echo "SET CHARACTER SET utf8mb4;"
            echo "SET GLOBAL character_set_client=utf8mb4;"
            echo "SET GLOBAL character_set_connection=utf8mb4;"
            echo "SET GLOBAL character_set_results=utf8mb4;"
            echo "SET FOREIGN_KEY_CHECKS=0;"
            echo ""
            cat "$temp_file"
            echo ""
            echo "SET FOREIGN_KEY_CHECKS=1;"
        } > "$output_file"

        rm -f "$temp_file"
        log_info "数据导出成功: $output_file"
        log_info "文件大小: $(du -h "$output_file" | cut -f1)"
    else
        rm -f "$temp_file"
        log_error "数据导出失败"
        exit 1
    fi
}

# 验证导出文件
verify_export() {
    log_info "验证导出文件..."

    local structure_file="${BACKUP_DIR}/${STRUCTURE_FILE}"
    local data_file="${BACKUP_DIR}/${DATA_FILE}"

    # 检查文件是否存在
    if [ ! -f "$structure_file" ]; then
        log_error "表结构文件不存在: $structure_file"
        exit 1
    fi

    if [ ! -f "$data_file" ]; then
        log_error "数据文件不存在: $data_file"
        exit 1
    fi

    # 检查字符集声明
    if ! grep -q "SET NAMES utf8mb4" "$structure_file"; then
        log_error "表结构文件缺少字符集声明"
        exit 1
    fi

    if ! grep -q "SET NAMES utf8mb4" "$data_file"; then
        log_error "数据文件缺少字符集声明"
        exit 1
    fi

    log_info "导出文件验证通过"
    log_info "表结构文件: $structure_file ($(du -h "$structure_file" | cut -f1))"
    log_info "数据文件: $data_file ($(du -h "$data_file" | cut -f1))"
}

# 导出数据库
export_database() {
    log_info "========== 开始导出数据库 =========="

    check_config
    check_mysqldump
    create_backup_dir
    export_structure
    export_data
    verify_export

    log_info "========== 数据库导出完成 =========="
}

# 使用帮助
show_usage() {
    echo "用法: $0 <command>"
    echo ""
    echo "命令:"
    echo "  export        导出数据库"
    echo "  help          显示帮助信息"
    echo ""
    echo "示例:"
    echo "  $0 export     # 导出数据库到 doc/database/backup/ 目录"
}

# 主函数
main() {
    case "$1" in
        export)
            export_database
            ;;
        help|--help|-h)
            show_usage
            ;;
        *)
            log_error "未知命令: $1"
            show_usage
            exit 1
            ;;
    esac
}

# 执行主函数
main "$@"

Step 2: 设置脚本执行权限

chmod +x export_database.sh

Step 3: 提交导出脚本

git add export_database.sh
git commit -m "feat: 创建数据库导出自动化脚本"

Task 4: 执行数据库导出

Files:

  • Generate: doc/database/backup/ccdi_structure.sql
  • Generate: doc/database/backup/ccdi_data.sql

Step 1: 创建配置文件

cp db_config.conf.template db_config.conf

Step 2: 验证配置文件内容

检查 db_config.conf 文件确保源数据库配置正确:

cat db_config.conf | grep "SOURCE_DB"

预期输出:

SOURCE_DB_HOST=116.62.17.81
SOURCE_DB_PORT=3306
SOURCE_DB_USER=root
SOURCE_DB_PASS=Kfcx@1234
SOURCE_DB_NAME=ccdi

Step 3: 执行导出脚本

./export_database.sh export

预期输出:

[INFO] 配置文件加载成功
[INFO] mysqldump 命令检查通过
[INFO] 开始导出表结构...
[INFO] 表结构导出成功: doc/database/backup/ccdi_structure.sql
[INFO] 文件大小: XXX
[INFO] 开始导出数据...
[INFO] 数据导出成功: doc/database/backup/ccdi_data.sql
[INFO] 文件大小: XXX
[INFO] 验证导出文件...
[INFO] 导出文件验证通过
[INFO] ========== 数据库导出完成 ==========

Step 4: 验证导出文件

检查表结构文件头部:

head -20 doc/database/backup/ccdi_structure.sql

预期输出应包含:

-- CCDI 数据库表结构
-- 导出时间: 2026-02-28 XX:XX:XX
-- 源数据库: 116.62.17.81:3306/ccdi
-- 字符集: utf8mb4

SET NAMES utf8mb4;
SET CHARACTER SET utf8mb4;
...

检查数据文件头部:

head -20 doc/database/backup/ccdi_data.sql

预期输出应包含:

-- CCDI 数据库数据
-- 导出时间: 2026-02-28 XX:XX:XX
-- 源数据库: 116.62.17.81:3306/ccdi
-- 字符集: utf8mb4

SET NAMES utf8mb4;
SET CHARACTER SET utf8mb4;
SET FOREIGN_KEY_CHECKS=0;
...

Step 5: 检查文件大小

ls -lh doc/database/backup/

预期输出应显示两个文件的大小。


Task 5: 添加导入功能到脚本

Files:

  • Modify: export_database.sh (添加导入函数)

Step 1: 在脚本中添加导入函数

export_database.sh 文件的 verify_export() 函数后添加以下函数:


# 导入表结构
import_structure() {
    local env_type=$1
    local db_host db_port db_user db_pass db_name

    case "$env_type" in
        production|prod)
            db_host="$PROD_DB_HOST"
            db_port="$PROD_DB_PORT"
            db_user="$PROD_DB_USER"
            db_pass="$PROD_DB_PASS"
            db_name="$PROD_DB_NAME"
            ;;
        test)
            db_host="$TEST_DB_HOST"
            db_port="$TEST_DB_PORT"
            db_user="$TEST_DB_USER"
            db_pass="$TEST_DB_PASS"
            db_name="$TEST_DB_NAME"
            ;;
        *)
            log_error "未知的环境类型: $env_type"
            exit 1
            ;;
    esac

    log_info "导入表结构到 ${env_type} 环境: ${db_host}:${db_port}/${db_name}"

    local structure_file="${BACKUP_DIR}/${STRUCTURE_FILE}"

    if [ ! -f "$structure_file" ]; then
        log_error "表结构文件不存在: $structure_file"
        log_info "请先执行导出: ./export_database.sh export"
        exit 1
    fi

    # 导入表结构
    mysql -h "$db_host" \
        -P "$db_port" \
        -u "$db_user" \
        -p"$db_pass" \
        --default-character-set=$CHARACTER_SET \
        "$db_name" < "$structure_file" 2>/dev/null

    if [ $? -eq 0 ]; then
        log_info "表结构导入成功"
    else
        log_error "表结构导入失败"
        exit 1
    fi
}

# 导入数据
import_data() {
    local env_type=$1
    local db_host db_port db_user db_pass db_name

    case "$env_type" in
        production|prod)
            db_host="$PROD_DB_HOST"
            db_port="$PROD_DB_PORT"
            db_user="$PROD_DB_USER"
            db_pass="$PROD_DB_PASS"
            db_name="$PROD_DB_NAME"
            ;;
        test)
            db_host="$TEST_DB_HOST"
            db_port="$TEST_DB_PORT"
            db_user="$TEST_DB_USER"
            db_pass="$TEST_DB_PASS"
            db_name="$TEST_DB_NAME"
            ;;
        *)
            log_error "未知的环境类型: $env_type"
            exit 1
            ;;
    esac

    log_info "导入数据到 ${env_type} 环境: ${db_host}:${db_port}/${db_name}"

    local data_file="${BACKUP_DIR}/${DATA_FILE}"

    if [ ! -f "$data_file" ]; then
        log_error "数据文件不存在: $data_file"
        log_info "请先执行导出: ./export_database.sh export"
        exit 1
    fi

    # 导入数据
    mysql -h "$db_host" \
        -P "$db_port" \
        -u "$db_user" \
        -p"$db_pass" \
        --default-character-set=$CHARACTER_SET \
        "$db_name" < "$data_file" 2>/dev/null

    if [ $? -eq 0 ]; then
        log_info "数据导入成功"
    else
        log_error "数据导入失败"
        exit 1
    fi
}

# 验证导入结果
verify_import() {
    local env_type=$1
    local db_host db_port db_user db_pass db_name

    case "$env_type" in
        production|prod)
            db_host="$PROD_DB_HOST"
            db_port="$PROD_DB_PORT"
            db_user="$PROD_DB_USER"
            db_pass="$PROD_DB_PASS"
            db_name="$PROD_DB_NAME"
            ;;
        test)
            db_host="$TEST_DB_HOST"
            db_port="$TEST_DB_PORT"
            db_user="$TEST_DB_USER"
            db_pass="$TEST_DB_PASS"
            db_name="$TEST_DB_NAME"
            ;;
        *)
            log_error "未知的环境类型: $env_type"
            exit 1
            ;;
    esac

    log_info "验证导入结果..."

    # 查询表数量
    local table_count=$(mysql -h "$db_host" \
        -P "$db_port" \
        -u "$db_user" \
        -p"$db_pass" \
        --default-character-set=$CHARACTER_SET \
        -N -e "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='$db_name';" "$db_name" 2>/dev/null)

    log_info "目标数据库表数量: $table_count"

    # 查询关键表行数示例sys_user 表)
    local user_count=$(mysql -h "$db_host" \
        -P "$db_port" \
        -u "$db_user" \
        -p"$db_pass" \
        --default-character-set=$CHARACTER_SET \
        -N -e "SELECT COUNT(*) FROM sys_user;" "$db_name" 2>/dev/null)

    log_info "sys_user 表数据行数: $user_count"

    # 检查数据库字符集
    local db_charset=$(mysql -h "$db_host" \
        -P "$db_port" \
        -u "$db_user" \
        -p"$db_pass" \
        --default-character-set=$CHARACTER_SET \
        -N -e "SELECT DEFAULT_CHARACTER_SET_NAME FROM information_schema.schemata WHERE schema_name='$db_name';" 2>/dev/null)

    log_info "数据库字符集: $db_charset"
}

# 导入数据库
import_database() {
    local env_type=$1

    if [ -z "$env_type" ]; then
        log_error "请指定目标环境: production 或 test"
        log_info "用法: $0 import [production|test]"
        exit 1
    fi

    log_info "========== 开始导入数据库到 ${env_type} 环境 =========="

    check_config
    import_structure "$env_type"
    import_data "$env_type"
    verify_import "$env_type"

    log_info "========== 数据库导入完成 =========="
}

Step 2: 更新 show_usage() 函数

替换 show_usage() 函数为:

# 使用帮助
show_usage() {
    echo "用法: $0 <command> [options]"
    echo ""
    echo "命令:"
    echo "  export              导出数据库"
    echo "  import <env>        导入数据库到指定环境"
    echo "  help                显示帮助信息"
    echo ""
    echo "环境:"
    echo "  production, prod    生产环境"
    echo "  test                测试环境"
    echo ""
    echo "示例:"
    echo "  $0 export           # 导出数据库到 doc/database/backup/ 目录"
    echo "  $0 import test      # 导入数据库到测试环境"
    echo "  $0 import prod      # 导入数据库到生产环境"
}

Step 3: 更新 main() 函数

替换 main() 函数为:

# 主函数
main() {
    case "$1" in
        export)
            export_database
            ;;
        import)
            import_database "$2"
            ;;
        help|--help|-h)
            show_usage
            ;;
        *)
            log_error "未知命令: $1"
            show_usage
            exit 1
            ;;
    esac
}

Step 4: 提交导入功能

git add export_database.sh
git commit -m "feat: 添加数据库导入功能到自动化脚本"

Task 6: 创建操作指南文档

Files:

  • Create: doc/database/backup/export_guide.md

Step 1: 创建操作指南文档

创建 doc/database/backup/export_guide.md 文件:

# CCDI 数据库迁移操作指南

## 概述

本文档提供 CCDI 纪检初核系统数据库迁移的详细操作步骤,包括从开发环境导出数据库和导入到生产/测试环境。

## 前置条件

### 必需工具
- MySQL 客户端工具(包含 mysqldump 和 mysql 命令)
- Bash shell 环境
- 网络访问权限(能连接源数据库和目标数据库)

### 检查 mysqldump 是否安装
```bash
mysqldump --version

如果未安装,请根据操作系统安装 MySQL 客户端:

  • Windows: 安装 MySQL Community Server
  • Linux (Ubuntu/Debian): sudo apt-get install mysql-client
  • Linux (CentOS/RHEL): sudo yum install mysql
  • macOS: brew install mysql-client

配置步骤

1. 创建配置文件

# 复制配置模板
cp db_config.conf.template db_config.conf

# 编辑配置文件
nano db_config.conf  # 或使用其他编辑器

2. 填写配置信息

编辑 db_config.conf 文件,填写以下信息:

源数据库(开发环境):

  • SOURCE_DB_HOST: 开发环境数据库地址
  • SOURCE_DB_PORT: 数据库端口(默认 3306
  • SOURCE_DB_USER: 数据库用户名
  • SOURCE_DB_PASS: 数据库密码
  • SOURCE_DB_NAME: 数据库名称ccdi

生产环境数据库:

  • PROD_DB_HOST: 生产环境数据库地址
  • PROD_DB_PORT: 数据库端口
  • PROD_DB_USER: 生产环境数据库用户名
  • PROD_DB_PASS: 生产环境数据库密码
  • PROD_DB_NAME: 数据库名称ccdi

测试环境数据库(可选):

  • TEST_DB_HOST: 测试环境数据库地址
  • TEST_DB_PORT: 数据库端口
  • TEST_DB_USER: 测试环境数据库用户名
  • TEST_DB_PASS: 测试环境数据库密码
  • TEST_DB_NAME: 数据库名称ccdi

3. 验证配置

检查配置文件格式:

cat db_config.conf | grep -E "^[A-Z]"

确保所有必需的配置项都已填写。

数据库导出

执行导出

./export_database.sh export

预期输出

[INFO] 配置文件加载成功
[INFO] mysqldump 命令检查通过
[INFO] 开始导出表结构...
[INFO] 表结构导出成功: doc/database/backup/ccdi_structure.sql
[INFO] 文件大小: XXX
[INFO] 开始导出数据...
[INFO] 数据导出成功: doc/database/backup/ccdi_data.sql
[INFO] 文件大小: XXX
[INFO] 验证导出文件...
[INFO] 导出文件验证通过
[INFO] ========== 数据库导出完成 ==========

验证导出文件

1. 检查文件是否存在

ls -lh doc/database/backup/

应该看到:

  • ccdi_structure.sql - 表结构文件
  • ccdi_data.sql - 数据文件

2. 检查字符集声明

head -20 doc/database/backup/ccdi_structure.sql

应该包含:

SET NAMES utf8mb4;
SET CHARACTER SET utf8mb4;

3. 检查文件内容

# 查看表结构
grep "CREATE TABLE" doc/database/backup/ccdi_structure.sql | wc -l

# 查看数据量INSERT 语句数量)
grep "INSERT" doc/database/backup/ccdi_data.sql | wc -l

数据库导入

准备工作

1. 确认目标数据库已创建

连接到目标数据库服务器:

mysql -h 目标IP -P 3306 -u 用户名 -p

创建数据库(如果不存在):

CREATE DATABASE ccdi CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;

2. 确认用户权限

目标数据库用户需要以下权限:

  • CREATE、ALTER、DROP创建和修改表
  • INSERT、UPDATE、DELETE数据操作
  • INDEX创建索引
  • REFERENCES外键约束

导入到测试环境

./export_database.sh import test

导入到生产环境

./export_database.sh import production

或简写:

./export_database.sh import prod

预期输出

[INFO] ========== 开始导入数据库到 test 环境 ==========
[INFO] 导入表结构到 test 环境: XXX:3306/ccdi
[INFO] 表结构导入成功
[INFO] 导入数据到 test 环境: XXX:3306/ccdi
[INFO] 数据导入成功
[INFO] 验证导入结果...
[INFO] 目标数据库表数量: XX
[INFO] sys_user 表数据行数: XX
[INFO] 数据库字符集: utf8mb4
[INFO] ========== 数据库导入完成 ==========

导入后验证

1. 验证表数量

连接到目标数据库:

mysql -h 目标IP -P 3306 -u 用户名 -p ccdi

查询表数量:

SELECT COUNT(*) FROM information_schema.tables
WHERE table_schema='ccdi';

对比源数据库和目标数据库的表数量是否一致。

2. 验证数据行数

查询各表数据行数:

SELECT table_name, table_rows
FROM information_schema.tables
WHERE table_schema='ccdi'
ORDER BY table_rows DESC
LIMIT 20;

对比源数据库和目标数据库的关键表行数。

3. 验证字符集

检查数据库字符集:

SHOW CREATE DATABASE ccdi;

应该显示:DEFAULT CHARACTER SET utf8mb4

检查表字符集:

SHOW CREATE TABLE sys_user;

应该显示:ENGINE=InnoDB DEFAULT CHARSET=utf8mb4

4. 验证中文数据

查询包含中文的数据:

-- 查询用户表
SELECT user_name, nick_name FROM sys_user LIMIT 10;

-- 查询字典数据
SELECT dict_label, dict_value FROM sys_dict_data LIMIT 10;

确保中文字符显示正常,无乱码。

5. 应用程序连接测试

修改应用程序配置文件连接到目标数据库,启动应用程序进行功能测试。

完整迁移流程示例

场景:从开发环境迁移到生产环境

1. 配置数据库连接

cp db_config.conf.template db_config.conf
nano db_config.conf
# 填写开发环境和生产环境数据库信息

2. 导出数据库

./export_database.sh export

3. 验证导出文件

ls -lh doc/database/backup/
head -20 doc/database/backup/ccdi_structure.sql

4. 先在测试环境验证

./export_database.sh import test

5. 验证测试环境

  • 连接测试数据库验证数据
  • 应用程序连接测试环境进行功能测试

6. 导入到生产环境

./export_database.sh import production

7. 验证生产环境

  • 连接生产数据库验证数据
  • 应用程序连接生产环境进行功能测试

8. 完成迁移

常见问题

1. mysqldump: command not found

原因: MySQL 客户端未安装或未添加到 PATH

解决:

  • 安装 MySQL 客户端工具
  • 或使用完整路径:/usr/bin/mysqldump

2. 配置文件不存在

错误信息: 配置文件不存在: db_config.conf

解决:

cp db_config.conf.template db_config.conf
# 编辑 db_config.conf 填写实际配置

3. 连接数据库失败

可能原因:

  • 数据库地址、端口、用户名或密码错误
  • 防火墙阻止连接
  • 数据库服务未启动

解决:

  • 检查配置文件中的连接信息
  • 使用 mysql 命令手动测试连接
  • 检查防火墙规则

4. 导入时字符集乱码

原因: 未正确指定字符集

解决:

  • 确保导出文件包含字符集声明
  • 导入命令添加 --default-character-set=utf8mb4 参数
  • 脚本已自动处理,如仍有问题请检查数据库默认字符集

5. 外键约束失败

错误信息: ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails

解决:

  • 脚本已自动添加 SET FOREIGN_KEY_CHECKS=0;SET FOREIGN_KEY_CHECKS=1;
  • 如仍有问题,请检查数据完整性

6. 数据包过大

错误信息: ERROR 1153 (08S01): Got a packet bigger than 'max_allowed_packet' bytes

解决:

  • 配置文件中的 MAX_ALLOWED_PACKET=512M 已处理此问题
  • 如数据量特别大,可增大此值

7. 权限不足

错误信息: ERROR 1044 (42000): Access denied for user

解决:

  • 使用具有足够权限的用户(如 root
  • 或授予用户必要权限

回滚方案

如果迁移失败或出现问题:

  1. 保留源数据库: 不要删除开发环境数据库
  2. 重新迁移: 修复问题后重新执行迁移流程
  3. 从备份恢复: 如生产环境有备份,可从备份恢复

注意事项

  1. 安全性:

    • db_config.conf 包含敏感信息,已添加到 .gitignore
    • 不要将配置文件提交到版本控制系统
    • 迁移完成后建议删除配置文件中的密码
  2. 性能:

    • 大数据库导出/导入可能需要较长时间
    • 建议在低峰期执行迁移
    • 确保有足够的磁盘空间
  3. 数据一致性:

    • 导出期间源数据库应避免写入操作
    • 或使用 --single-transaction 参数(已包含)
  4. 字符集:

    • 确保所有步骤都使用 utf8mb4 字符集
    • 验证阶段重点检查中文数据

技术支持

如遇到问题:

  1. 检查本文档的常见问题部分
  2. 查看脚本执行的错误信息
  3. 检查数据库连接和权限
  4. 查看数据库日志

相关文件

  • 自动化脚本: export_database.sh
  • 配置模板: db_config.conf.template
  • 实际配置: db_config.conf
  • 表结构文件: doc/database/backup/ccdi_structure.sql
  • 数据文件: doc/database/backup/ccdi_data.sql
  • 设计文档: docs/plans/2026-02-28-database-migration-design.md

**Step 2: 提交操作指南**

```bash
git add doc/database/backup/export_guide.md
git commit -m "docs: 添加数据库迁移操作指南"

Task 7: 完整验证流程

Files:

  • 无文件修改,仅验证操作

Step 1: 验证脚本帮助信息

./export_database.sh help

预期输出:

用法: ./export_database.sh <command> [options]

命令:
  export              导出数据库
  import <env>        导入数据库到指定环境
  help                显示帮助信息

环境:
  production, prod    生产环境
  test                测试环境

示例:
  ./export_database.sh export           # 导出数据库到 doc/database/backup/ 目录
  ./export_database.sh import test      # 导入数据库到测试环境
  ./export_database.sh import prod      # 导入数据库到生产环境

Step 2: 验证配置文件

cat db_config.conf

确保包含所有必需配置项。

Step 3: 验证导出文件

# 检查文件存在
ls -lh doc/database/backup/ccdi_*.sql

# 检查文件内容
head -30 doc/database/backup/ccdi_structure.sql
head -30 doc/database/backup/ccdi_data.sql

# 统计表数量
grep "CREATE TABLE" doc/database/backup/ccdi_structure.sql | wc -l

# 统计 INSERT 语句
grep "INSERT INTO" doc/database/backup/ccdi_data.sql | wc -l

Step 4: 创建验证报告

创建临时验证报告:

cat > /tmp/migration_verify.txt << 'EOF'
数据库迁移验证报告
==================
导出时间: $(date)

文件信息:
- 表结构文件: $(ls -lh doc/database/backup/ccdi_structure.sql)
- 数据文件: $(ls -lh doc/database/backup/ccdi_data.sql)

表数量: $(grep "CREATE TABLE" doc/database/backup/ccdi_structure.sql | wc -l)

字符集检查:
$(grep "SET NAMES utf8mb4" doc/database/backup/ccdi_structure.sql)

验证结果: 通过
EOF
cat /tmp/migration_verify.txt

成功标准

完成后,应满足以下所有条件:

  1. 配置文件模板 db_config.conf.template 已创建
  2. db_config.conf 已添加到 .gitignore
  3. 自动化脚本 export_database.sh 可执行
  4. 执行 ./export_database.sh export 成功生成两个 SQL 文件
  5. ccdi_structure.sql 包含所有表结构和字符集声明
  6. ccdi_data.sql 包含所有数据和字符集声明
  7. SQL 文件无乱码,字符集正确
  8. 操作指南文档清晰完整
  9. 所有代码已提交到 Git

执行建议

建议执行顺序

  1. 在测试环境完整执行一遍流程
  2. 验证测试环境导入的数据完整性
  3. 确认无问题后,在生产环境执行
  4. 验证生产环境数据完整性
  5. 应用程序连接测试

时间估算

  • Task 1-3: 15分钟脚本开发
  • Task 4: 20-30分钟导出执行取决于数据量
  • Task 5: 10分钟添加导入功能
  • Task 6-7: 15分钟文档和验证

总计: 约 60-70 分钟