Files
asd-backend/scripts/migrate-prod-to-dev.sh

124 lines
4.8 KiB
Bash
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
# ===========================================
# 数据迁移脚本: milkydata → milkydata_dev
# 用途: 将生产库 milkydata 的数据迁移到 milkydata_dev
# 自动处理列名差异 (is_paid → is_member, paid_expires_at → membership_expires_at)
# 注意: 目标库 milkydata_dev 中已存在的数据会被清空
# ===========================================
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
DB_CONTAINER="1Panel-postgresql-FtMo"
DB_USER="milkydata"
SRC_DB="milkydata"
DST_DB="milkydata_dev"
BACKUP_DIR="${PROJECT_ROOT}/backups"
mkdir -p "$BACKUP_DIR"
LOG_FILE="${BACKUP_DIR}/migration_$(date +%Y%m%d_%H%M%S).log"
log() { echo "[$(date '+%H:%M:%S')] $1" | tee -a "$LOG_FILE"; }
echo "═══════════════════════════════════════"
echo " 数据迁移: ${SRC_DB}${DST_DB}"
echo "═══════════════════════════════════════"
# ---------- 步骤 0: 确认 ----------
echo ""
echo "源库: ${SRC_DB}"
docker exec "$DB_CONTAINER" psql -U "$DB_USER" -d "$SRC_DB" -tAc "
SELECT CONCAT(' users: ', COUNT(*), ' 行') FROM users;
SELECT CONCAT(' weather_data: ', COUNT(*), ' 行') FROM weather_data;
SELECT CONCAT(' payment_orders: ', COUNT(*), ' 行') FROM payment_orders;
"
echo ""
echo "目标库: ${DST_DB}(数据将被清空并重新导入)"
echo ""
read -p "确认迁移? [y/N] " -n 1 -r; echo
[[ ! $REPLY =~ ^[Yy]$ ]] && { echo "已取消"; exit 0; }
# ---------- 步骤 1: 备份目标库 ----------
log "备份目标库 ${DST_DB}..."
docker exec "$DB_CONTAINER" pg_dump -U "$DB_USER" -d "$DST_DB" -Fc \
> "${BACKUP_DIR}/${DST_DB}_pre_migration_$(date +%Y%m%d_%H%M%S).dump" 2>> "$LOG_FILE"
log " 目标库备份完成 ✅"
# ---------- 步骤 2: 清空目标库 ----------
log "清空目标库 ${DST_DB}..."
docker exec "$DB_CONTAINER" psql -U "$DB_USER" -d "$DST_DB" -tAc "
TRUNCATE weather_data CASCADE;
TRUNCATE payment_orders CASCADE;
TRUNCATE notifications CASCADE;
TRUNCATE payment_audit_log CASCADE;
DELETE FROM users CASCADE;
" 2>> "$LOG_FILE"
log " 清空完成 ✅"
# ---------- 步骤 3: 导出源库数据到 SQL 文件 ----------
log "导出源库数据..."
TMP_SQL="/tmp/migrate_$$.sql"
# users 表(列名转换: is_paid → is_member, paid_expires_at → membership_expires_at
docker exec "$DB_CONTAINER" pg_dump -U "$DB_USER" -d "$SRC_DB" \
--data-only --table=users --column-inserts 2>/dev/null \
| grep -v '^--' | grep -v '^$' \
| sed 's/ is_paid/ is_member/g' \
| sed 's/ paid_expires_at/ membership_expires_at/g' \
> "$TMP_SQL"
log " users 导出并转换列名 ✅"
# weather_data
docker exec "$DB_CONTAINER" pg_dump -U "$DB_USER" -d "$SRC_DB" \
--data-only --table=weather_data --column-inserts 2>/dev/null \
| grep -v '^--' | grep -v '^$' >> "$TMP_SQL"
log " weather_data 导出 ✅"
# payment_orders
docker exec "$DB_CONTAINER" pg_dump -U "$DB_USER" -d "$SRC_DB" \
--data-only --table=payment_orders --column-inserts 2>/dev/null \
| grep -v '^--' | grep -v '^$' >> "$TMP_SQL"
log " payment_orders 导出 ✅"
log "$(wc -l < "$TMP_SQL") 条 SQL 语句"
# ---------- 步骤 4: 导入到目标库 ----------
log "导入数据到 ${DST_DB}..."
docker exec -i "$DB_CONTAINER" psql -U "$DB_USER" -d "$DST_DB" < "$TMP_SQL" 2>> "$LOG_FILE"
log " 导入完成 ✅"
# ---------- 步骤 5: 重置自增序列 ----------
log "重置自增序列..."
docker exec "$DB_CONTAINER" psql -U "$DB_USER" -d "$DST_DB" -tAc "
SELECT SETVAL('users_id_seq', COALESCE((SELECT MAX(id) FROM users), 1));
SELECT SETVAL('weather_data_id_seq', COALESCE((SELECT MAX(id) FROM weather_data), 1));
SELECT SETVAL('payment_orders_id_seq', COALESCE((SELECT MAX(id) FROM payment_orders), 1));
" 2>> "$LOG_FILE"
log " 序列重置完成 ✅"
# ---------- 清理 ----------
rm -f "$TMP_SQL"
# ---------- 验证 ----------
echo ""
log "═════════════════════════════════"
log "迁移完成!源库 vs 目标库数据量:"
log "═════════════════════════════════"
for table in users weather_data payment_orders; do
src=$(docker exec "$DB_CONTAINER" psql -U "$DB_USER" -d "$SRC_DB" -tAc "SELECT COUNT(*) FROM ${table};" 2>/dev/null)
dst=$(docker exec "$DB_CONTAINER" psql -U "$DB_USER" -d "$DST_DB" -tAc "SELECT COUNT(*) FROM ${table};" 2>/dev/null)
status="✅"
[ "$src" != "$dst" ] && status="❌ 不匹配!"
log " ${table}: ${src}${dst} ${status}"
done
echo ""
echo "日志: ${LOG_FILE}"
echo "备份: ${BACKUP_DIR}/${DST_DB}_pre_migration_*.dump"
echo ""
echo "⚠️ 如需回滚:
docker exec -i ${DB_CONTAINER} pg_restore -U ${DB_USER} -d ${DST_DB} --clean \n < ${BACKUP_DIR}/${DST_DB}_pre_migration_*.dump"