191 lines
6.8 KiB
Bash
Executable File
191 lines
6.8 KiB
Bash
Executable File
#!/bin/bash
|
|
# 表结构对齐脚本 - 准生产 → VPS
|
|
# 支持单表模式,避免全量同步
|
|
|
|
# 不使用 set -e,手动处理错误
|
|
|
|
# 连接信息
|
|
SOURCE_HOST="100.115.195.188"
|
|
SOURCE_PORT="50036"
|
|
SOURCE_USER="witsoftd"
|
|
TARGET_HOST="101.34.227.188"
|
|
TARGET_PORT="3306"
|
|
TARGET_USER="root"
|
|
|
|
# 颜色输出
|
|
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"; }
|
|
|
|
usage() {
|
|
echo "用法:$0 <database> <table>"
|
|
echo " $0 <database> # 同步整个库"
|
|
echo ""
|
|
echo "示例:"
|
|
echo " $0 dmp_serp idb_pub_basic_item_info # 单表同步"
|
|
echo " $0 dmp_serp # 全库同步"
|
|
exit 1
|
|
}
|
|
|
|
[ -z "$1" ] && usage
|
|
|
|
SOURCE_DB="$1"
|
|
TABLE="$2"
|
|
TARGET_DB="${3:-$SOURCE_DB}" # 可选第三个参数指定目标库名,默认同源库名
|
|
|
|
# 检查环境变量
|
|
if [ -z "$MYSQL_PWD_WIT" ]; then
|
|
log_error "缺少环境变量 MYSQL_PWD_WIT"
|
|
exit 1
|
|
fi
|
|
if [ -z "$MYSQL_PWD_SQL" ]; then
|
|
log_error "缺少环境变量 MYSQL_PWD_SQL"
|
|
exit 1
|
|
fi
|
|
|
|
# 输出目录
|
|
DATE=$(date +%Y%m%d)
|
|
OUTPUT_DIR="/home/yangxuan/codes/xuan-sql/scripts/${DATE}"
|
|
mkdir -p "$OUTPUT_DIR"
|
|
|
|
log_info "同步方向:准生产 (${SOURCE_HOST}:${SOURCE_PORT}) → VPS (${TARGET_HOST}:${TARGET_PORT})"
|
|
log_info "数据库:${SOURCE_DB}"
|
|
[ -n "$TABLE" ] && log_info "表:${TABLE} (单表模式)"
|
|
|
|
# 获取表列表
|
|
if [ -n "$TABLE" ]; then
|
|
# 单表模式
|
|
log_info "单表模式:只同步 ${TABLE}"
|
|
TABLES="$TABLE"
|
|
else
|
|
# 全库模式
|
|
log_info "全库模式:获取表列表..."
|
|
TABLES=$(mysql -h "$SOURCE_HOST" -P "$SOURCE_PORT" -u "$SOURCE_USER" -p"${MYSQL_PWD_WIT}" -D "$SOURCE_DB" -N -e "SHOW TABLES;")
|
|
TABLE_COUNT=$(echo "$TABLES" | wc -l)
|
|
log_info "共 ${TABLE_COUNT} 张表"
|
|
|
|
if [ "$TABLE_COUNT" -gt 50 ]; then
|
|
log_warn "表数量超过 50,确认继续?(y/n)"
|
|
read -r CONFIRM
|
|
[ "$CONFIRM" != "y" ] && exit 0
|
|
fi
|
|
fi
|
|
|
|
# 同步单表函数
|
|
sync_single_table() {
|
|
local TABLE_NAME="$1"
|
|
local SCRIPT_FILE="${OUTPUT_DIR}/${SOURCE_DB}__${TABLE_NAME}__struct.sql"
|
|
|
|
log_info "处理:${TABLE_NAME}"
|
|
|
|
# 检查源表是否存在
|
|
SOURCE_EXISTS=$(mysql -h "$SOURCE_HOST" -P "$SOURCE_PORT" -u "$SOURCE_USER" -p"${MYSQL_PWD_WIT}" -D "$SOURCE_DB" -N -e \
|
|
"SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA='$SOURCE_DB' AND TABLE_NAME='$TABLE_NAME';")
|
|
|
|
if [ "$SOURCE_EXISTS" -eq 0 ]; then
|
|
log_error "源表 ${SOURCE_DB}.${TABLE_NAME} 不存在"
|
|
return 1
|
|
fi
|
|
|
|
# 检查目标表是否存在
|
|
TARGET_EXISTS=$(mysql -h "$TARGET_HOST" -P "$TARGET_PORT" -u "$TARGET_USER" -p"${MYSQL_PWD_SQL}" -D "$TARGET_DB" -N -e \
|
|
"SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA='$TARGET_DB' AND TABLE_NAME='$TABLE_NAME';")
|
|
|
|
# 获取源表结构(去除字面量 \n,转换为真实换行;cut -f2 取 CREATE 语句列)
|
|
SOURCE_CREATE=$(mysql -h "$SOURCE_HOST" -P "$SOURCE_PORT" -u "$SOURCE_USER" -p"${MYSQL_PWD_WIT}" -D "$SOURCE_DB" -N -e "SHOW CREATE TABLE \`${TABLE_NAME}\`;" | cut -f2 | sed 's/\\n/\n/g')
|
|
|
|
if [ "$TARGET_EXISTS" -eq 0 ]; then
|
|
# 表不存在 → CREATE
|
|
log_info " 目标表不存在,使用 CREATE TABLE"
|
|
# 提取 CREATE TABLE 语句的主体部分(删除第一行和最后一行)
|
|
TABLE_BODY=$(echo "$SOURCE_CREATE" | sed '1d;$d')
|
|
cat > "$SCRIPT_FILE" <<EOF
|
|
-- ============================================================
|
|
-- 表结构同步:${TABLE_NAME}
|
|
-- 源:准生产 (${SOURCE_HOST}:${SOURCE_PORT})
|
|
-- 目标:VPS (${TARGET_HOST}:${TARGET_PORT}) ${TARGET_DB}
|
|
-- 生成时间:$(date '+%Y-%m-%d %H:%M:%S')
|
|
-- ============================================================
|
|
|
|
CREATE TABLE IF NOT EXISTS \`${TARGET_DB}\`.\`${TABLE_NAME}\` (
|
|
$TABLE_BODY
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='同步自准生产'
|
|
EOF
|
|
else
|
|
# 表存在 → 对比差异
|
|
log_info " 目标表已存在,对比结构差异..."
|
|
|
|
# 获取字段差异
|
|
DIFF_FIELDS=$(mysql -h "$SOURCE_HOST" -P "$SOURCE_PORT" -u "$SOURCE_USER" -p"${MYSQL_PWD_WIT}" -D "$SOURCE_DB" -N -e "
|
|
SELECT COLUMN_NAME, COLUMN_TYPE, IS_NULLABLE, COLUMN_DEFAULT, COLUMN_COMMENT
|
|
FROM information_schema.COLUMNS
|
|
WHERE TABLE_SCHEMA='$SOURCE_DB' AND TABLE_NAME='$TABLE_NAME'
|
|
ORDER BY ORDINAL_POSITION;
|
|
" | md5sum)
|
|
|
|
TARGET_DIFF=$(mysql -h "$TARGET_HOST" -P "$TARGET_PORT" -u "$TARGET_USER" -p"${MYSQL_PWD_SQL}" -D "$TARGET_DB" -N -e "
|
|
SELECT COLUMN_NAME, COLUMN_TYPE, IS_NULLABLE, COLUMN_DEFAULT, COLUMN_COMMENT
|
|
FROM information_schema.COLUMNS
|
|
WHERE TABLE_SCHEMA='$TARGET_DB' AND TABLE_NAME='$TABLE_NAME'
|
|
ORDER BY ORDINAL_POSITION;
|
|
" | md5sum)
|
|
|
|
if [ "$DIFF_FIELDS" = "$TARGET_DIFF" ]; then
|
|
log_info " 结构一致,跳过"
|
|
return 0
|
|
fi
|
|
|
|
log_warn " 发现差异,生成 ALTER 脚本..."
|
|
# TODO: 生成精确的 ALTER 语句
|
|
SOURCE_STRUCT=$(mysql -h "$SOURCE_HOST" -P "$SOURCE_PORT" -u "$SOURCE_USER" -p"${MYSQL_PWD_WIT}" -D "$SOURCE_DB" -N -e "SHOW CREATE TABLE \`$TABLE_NAME\`;" 2>/dev/null | tail -1 || echo "无法获取")
|
|
TARGET_STRUCT=$(mysql -h "$TARGET_HOST" -P "$TARGET_PORT" -u "$TARGET_USER" -p"${MYSQL_PWD_SQL}" -D "$TARGET_DB" -N -e "SHOW CREATE TABLE \`$TABLE_NAME\`;" 2>/dev/null | tail -1 || echo "无法获取")
|
|
cat > "$SCRIPT_FILE" <<EOF
|
|
-- ============================================================
|
|
-- 表结构修改:${TABLE_NAME}
|
|
-- 源:准生产 (${SOURCE_HOST}:${SOURCE_PORT})
|
|
-- 目标:VPS (${TARGET_HOST}:${TARGET_PORT}) ${TARGET_DB}
|
|
-- 生成时间:$(date '+%Y-%m-%d %H:%M:%S')
|
|
-- ============================================================
|
|
-- ⚠️ 需要人工对比差异后手动完善 ALTER 语句
|
|
|
|
-- 源表结构:
|
|
-- $SOURCE_STRUCT
|
|
|
|
-- 目标表结构:
|
|
-- $TARGET_STRUCT
|
|
|
|
-- ALTER TABLE \`${TARGET_DB}\`.\`${TABLE_NAME}\` ...;
|
|
EOF
|
|
fi
|
|
|
|
# 执行脚本
|
|
if [ -f "$SCRIPT_FILE" ]; then
|
|
log_info " 执行脚本:${SCRIPT_FILE}"
|
|
if mysql -h "$TARGET_HOST" -P "$TARGET_PORT" -u "$TARGET_USER" -p"${MYSQL_PWD_SQL}" < "$SCRIPT_FILE" 2>&1; then
|
|
log_info " ✅ 成功"
|
|
else
|
|
log_error " ❌ 失败,查看脚本:${SCRIPT_FILE}"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# 执行同步
|
|
FAILED=0
|
|
SUCCESS=0
|
|
|
|
for TABLE_NAME in $TABLES; do
|
|
if sync_single_table "$TABLE_NAME"; then
|
|
((SUCCESS++))
|
|
else
|
|
((FAILED++))
|
|
fi
|
|
done
|
|
|
|
log_info "完成!成功:${SUCCESS}, 失败:${FAILED}"
|
|
log_info "脚本目录:${OUTPUT_DIR}"
|