# 数据库迁移实施计划 > **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` 文件: ```bash # 数据库迁移配置文件模板 # 使用方法:复制此文件为 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: 提交配置模板** ```bash git add db_config.conf.template .gitignore git commit -m "feat: 添加数据库迁移配置模板和安全措施" ``` --- ## Task 2: 创建备份目录结构 **Files:** - Create: `doc/database/backup/.gitkeep` **Step 1: 创建备份目录** ```bash mkdir -p doc/database/backup ``` **Step 2: 创建 .gitkeep 文件保持目录** ```bash touch doc/database/backup/.gitkeep ``` **Step 3: 提交目录结构** ```bash git add doc/database/backup/.gitkeep git commit -m "feat: 创建数据库备份目录结构" ``` --- ## Task 3: 创建自动化导出脚本(框架和导出功能) **Files:** - Create: `export_database.sh` **Step 1: 创建脚本文件并添加基本框架** 创建 `export_database.sh` 文件: ```bash #!/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 " 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: 设置脚本执行权限** ```bash chmod +x export_database.sh ``` **Step 3: 提交导出脚本** ```bash 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: 创建配置文件** ```bash cp db_config.conf.template db_config.conf ``` **Step 2: 验证配置文件内容** 检查 `db_config.conf` 文件确保源数据库配置正确: ```bash 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: 执行导出脚本** ```bash ./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: 验证导出文件** 检查表结构文件头部: ```bash head -20 doc/database/backup/ccdi_structure.sql ``` 预期输出应包含: ```sql -- CCDI 数据库表结构 -- 导出时间: 2026-02-28 XX:XX:XX -- 源数据库: 116.62.17.81:3306/ccdi -- 字符集: utf8mb4 SET NAMES utf8mb4; SET CHARACTER SET utf8mb4; ... ``` 检查数据文件头部: ```bash head -20 doc/database/backup/ccdi_data.sql ``` 预期输出应包含: ```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: 检查文件大小** ```bash ls -lh doc/database/backup/ ``` 预期输出应显示两个文件的大小。 --- ## Task 5: 添加导入功能到脚本 **Files:** - Modify: `export_database.sh` (添加导入函数) **Step 1: 在脚本中添加导入函数** 在 `export_database.sh` 文件的 `verify_export()` 函数后添加以下函数: ```bash # 导入表结构 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()` 函数为: ```bash # 使用帮助 show_usage() { echo "用法: $0 [options]" echo "" echo "命令:" echo " export 导出数据库" echo " import 导入数据库到指定环境" 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()` 函数为: ```bash # 主函数 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: 提交导入功能** ```bash 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` 文件: ```markdown # 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. 创建配置文件 ```bash # 复制配置模板 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. 验证配置 检查配置文件格式: ```bash cat db_config.conf | grep -E "^[A-Z]" ``` 确保所有必需的配置项都已填写。 ## 数据库导出 ### 执行导出 ```bash ./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. 检查文件是否存在** ```bash ls -lh doc/database/backup/ ``` 应该看到: - `ccdi_structure.sql` - 表结构文件 - `ccdi_data.sql` - 数据文件 **2. 检查字符集声明** ```bash head -20 doc/database/backup/ccdi_structure.sql ``` 应该包含: ```sql SET NAMES utf8mb4; SET CHARACTER SET utf8mb4; ``` **3. 检查文件内容** ```bash # 查看表结构 grep "CREATE TABLE" doc/database/backup/ccdi_structure.sql | wc -l # 查看数据量(INSERT 语句数量) grep "INSERT" doc/database/backup/ccdi_data.sql | wc -l ``` ## 数据库导入 ### 准备工作 **1. 确认目标数据库已创建** 连接到目标数据库服务器: ```bash mysql -h 目标IP -P 3306 -u 用户名 -p ``` 创建数据库(如果不存在): ```sql CREATE DATABASE ccdi CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; ``` **2. 确认用户权限** 目标数据库用户需要以下权限: - CREATE、ALTER、DROP(创建和修改表) - INSERT、UPDATE、DELETE(数据操作) - INDEX(创建索引) - REFERENCES(外键约束) ### 导入到测试环境 ```bash ./export_database.sh import test ``` ### 导入到生产环境 ```bash ./export_database.sh import production ``` 或简写: ```bash ./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. 验证表数量 连接到目标数据库: ```bash mysql -h 目标IP -P 3306 -u 用户名 -p ccdi ``` 查询表数量: ```sql SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='ccdi'; ``` 对比源数据库和目标数据库的表数量是否一致。 ### 2. 验证数据行数 查询各表数据行数: ```sql SELECT table_name, table_rows FROM information_schema.tables WHERE table_schema='ccdi' ORDER BY table_rows DESC LIMIT 20; ``` 对比源数据库和目标数据库的关键表行数。 ### 3. 验证字符集 检查数据库字符集: ```sql SHOW CREATE DATABASE ccdi; ``` 应该显示:`DEFAULT CHARACTER SET utf8mb4` 检查表字符集: ```sql SHOW CREATE TABLE sys_user; ``` 应该显示:`ENGINE=InnoDB DEFAULT CHARSET=utf8mb4` ### 4. 验证中文数据 查询包含中文的数据: ```sql -- 查询用户表 SELECT user_name, nick_name FROM sys_user LIMIT 10; -- 查询字典数据 SELECT dict_label, dict_value FROM sys_dict_data LIMIT 10; ``` 确保中文字符显示正常,无乱码。 ### 5. 应用程序连接测试 修改应用程序配置文件连接到目标数据库,启动应用程序进行功能测试。 ## 完整迁移流程示例 ### 场景:从开发环境迁移到生产环境 **1. 配置数据库连接** ```bash cp db_config.conf.template db_config.conf nano db_config.conf # 填写开发环境和生产环境数据库信息 ``` **2. 导出数据库** ```bash ./export_database.sh export ``` **3. 验证导出文件** ```bash ls -lh doc/database/backup/ head -20 doc/database/backup/ccdi_structure.sql ``` **4. 先在测试环境验证** ```bash ./export_database.sh import test ``` **5. 验证测试环境** - 连接测试数据库验证数据 - 应用程序连接测试环境进行功能测试 **6. 导入到生产环境** ```bash ./export_database.sh import production ``` **7. 验证生产环境** - 连接生产数据库验证数据 - 应用程序连接生产环境进行功能测试 **8. 完成迁移** ## 常见问题 ### 1. mysqldump: command not found **原因**: MySQL 客户端未安装或未添加到 PATH **解决**: - 安装 MySQL 客户端工具 - 或使用完整路径:`/usr/bin/mysqldump` ### 2. 配置文件不存在 **错误信息**: `配置文件不存在: db_config.conf` **解决**: ```bash 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: 验证脚本帮助信息** ```bash ./export_database.sh help ``` 预期输出: ``` 用法: ./export_database.sh [options] 命令: export 导出数据库 import 导入数据库到指定环境 help 显示帮助信息 环境: production, prod 生产环境 test 测试环境 示例: ./export_database.sh export # 导出数据库到 doc/database/backup/ 目录 ./export_database.sh import test # 导入数据库到测试环境 ./export_database.sh import prod # 导入数据库到生产环境 ``` **Step 2: 验证配置文件** ```bash cat db_config.conf ``` 确保包含所有必需配置项。 **Step 3: 验证导出文件** ```bash # 检查文件存在 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: 创建验证报告** 创建临时验证报告: ```bash 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 分钟