cosmo/backend/scripts/upgrade_final.sh

250 lines
7.4 KiB
Bash
Raw Normal View History

2025-12-27 10:28:15 +00:00
#!/bin/bash
# ============================================================
# 生产数据库终极升级脚本
# ============================================================
# 使用 session_replication_role 绕过外键约束
# 大幅提升升级速度和成功率
# ============================================================
set -e
# 配置
CONTAINER="cosmo_postgres"
DB_NAME="cosmo_db"
DB_USER="postgres"
BACKUP_FILE="backup_$(date +%Y%m%d_%H%M%S).sql"
SCRIPT_FILE="upgrade_production_final.sql"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# 颜色
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
NC='\033[0m'
print_info() { echo -e "${BLUE} ${1}${NC}"; }
print_success() { echo -e "${GREEN}${1}${NC}"; }
print_warning() { echo -e "${YELLOW}⚠️ ${1}${NC}"; }
print_error() { echo -e "${RED}${1}${NC}"; }
print_step() { echo -e "${CYAN}${1}${NC}"; }
# 检查容器
check_container() {
print_step "检查 Docker 容器状态..."
if ! docker ps --format '{{.Names}}' | grep -q "^${CONTAINER}$"; then
print_error "容器 ${CONTAINER} 未运行!"
docker ps --format "table {{.Names}}\t{{.Status}}"
exit 1
fi
print_success "容器运行正常"
}
# 检查脚本
check_script() {
print_step "检查升级脚本..."
if [ ! -f "${SCRIPT_DIR}/${SCRIPT_FILE}" ]; then
print_error "找不到 ${SCRIPT_FILE}"
exit 1
fi
print_success "脚本就绪"
}
# 检查权限
check_permissions() {
print_step "检查数据库权限..."
SUPERUSER=$(docker exec ${CONTAINER} psql -U ${DB_USER} -d ${DB_NAME} -t -c \
"SELECT usesuper FROM pg_user WHERE usename = current_user;" | tr -d ' ')
if [ "$SUPERUSER" != "t" ]; then
print_error "用户 ${DB_USER} 不是 superuser"
echo ""
print_warning "session_replication_role 需要 superuser 权限"
echo "解决方案:"
echo " 1. 使用 superuser 账号执行升级"
echo " 2. 或临时授予权限: ALTER USER ${DB_USER} WITH SUPERUSER;"
exit 1
fi
print_success "权限检查通过 (superuser)"
}
# 检查 display_name 字段
check_display_name() {
print_step "检查 roles 表结构..."
HAS_DISPLAY_NAME=$(docker exec ${CONTAINER} psql -U ${DB_USER} -d ${DB_NAME} -t -c \
"SELECT COUNT(*) FROM information_schema.columns
WHERE table_name = 'roles' AND column_name = 'display_name';" | tr -d ' ')
if [ "$HAS_DISPLAY_NAME" = "1" ]; then
print_info "检测到 display_name 字段(将使用对应版本)"
echo ""
print_warning "请确认 upgrade_production_final.sql 中:"
echo " - 第 20-27 行(带 display_name未注释"
echo " - 第 29-36 行(不带 display_name已注释"
echo ""
read -p "是否确认脚本已正确配置? (yes/no): " confirm
if [ "$confirm" != "yes" ]; then
print_info "升级已取消,请检查脚本配置"
exit 0
fi
else
print_info "未检测到 display_name 字段"
echo ""
print_warning "请确认 upgrade_production_final.sql 中:"
echo " - 第 20-27 行(带 display_name已注释"
echo " - 第 29-36 行(不带 display_name未注释"
echo ""
read -p "是否确认脚本已正确配置? (yes/no): " confirm
if [ "$confirm" != "yes" ]; then
print_info "升级已取消,请检查脚本配置"
exit 0
fi
fi
}
# 备份数据库
backup_database() {
print_step "备份数据库..."
if docker exec ${CONTAINER} pg_dump -U ${DB_USER} -d ${DB_NAME} > "${SCRIPT_DIR}/${BACKUP_FILE}"; then
SIZE=$(ls -lh "${SCRIPT_DIR}/${BACKUP_FILE}" | awk '{print $5}')
print_success "备份完成: ${BACKUP_FILE} (${SIZE})"
else
print_error "备份失败!"
exit 1
fi
}
# 执行升级
execute_upgrade() {
print_step "执行数据库升级..."
echo "========================================================"
if cat "${SCRIPT_DIR}/${SCRIPT_FILE}" | docker exec -i ${CONTAINER} psql -U ${DB_USER} -d ${DB_NAME}; then
echo "========================================================"
print_success "升级执行完成!"
return 0
else
echo "========================================================"
print_error "升级失败!"
return 1
fi
}
# 显示验证结果
show_verification() {
print_step "数据验证..."
echo ""
docker exec ${CONTAINER} psql -U ${DB_USER} -d ${DB_NAME} -c "
SELECT
'celestial_bodies.short_name' as item,
CASE WHEN EXISTS(
SELECT 1 FROM information_schema.columns
WHERE table_name='celestial_bodies' AND column_name='short_name'
) THEN '✓ 存在' ELSE '✗ 缺失' END as status
UNION ALL
SELECT
'roles',
COUNT(*)::text || ' 条记录'
FROM roles
UNION ALL
SELECT
'menus',
COUNT(*)::text || ' 条记录'
FROM menus
UNION ALL
SELECT
'role_menus',
COUNT(*)::text || ' 条记录'
FROM role_menus
UNION ALL
SELECT
'scheduled_jobs',
COUNT(*)::text || ' 条记录'
FROM scheduled_jobs
UNION ALL
SELECT
'system_settings',
COUNT(*)::text || ' 条记录'
FROM system_settings;
" -t
echo ""
}
# 显示回滚信息
show_rollback_info() {
echo ""
print_warning "如需回滚,执行:"
echo "cat ${SCRIPT_DIR}/${BACKUP_FILE} | docker exec -i ${CONTAINER} psql -U ${DB_USER} -d ${DB_NAME}"
echo ""
}
# 主函数
main() {
echo "============================================================"
echo " 生产数据库终极升级脚本"
echo " 使用 session_replication_role 技术"
echo "============================================================"
echo ""
# 检查
check_container
check_script
check_permissions
check_display_name
# 确认
echo ""
print_warning "即将执行以下操作:"
echo " 1. 备份当前数据库"
echo " 2. 使用 replica 模式绕过外键约束"
echo " 3. 导入所有数据(无需关心顺序)"
echo " 4. 恢复正常模式并验证数据完整性"
echo ""
echo "受影响的表:"
echo " • celestial_bodies - 添加 short_name 字段"
echo " • roles - 创建/更新记录"
echo " • menus - 清空并重新导入 (14条)"
echo " • role_menus - 清空并重新导入 (16条)"
echo " • celestial_events - 清空"
echo " • scheduled_jobs - 清空并重新导入 (2条)"
echo " • system_settings - 导入/更新 (3条)"
echo " • user_roles - 为现有用户分配角色"
echo ""
read -p "是否继续? (yes/no): " confirm
if [ "$confirm" != "yes" ]; then
print_info "升级已取消"
exit 0
fi
# 执行
echo ""
backup_database
if execute_upgrade; then
show_verification
print_success "🎉 数据库升级成功!"
show_rollback_info
echo ""
print_info "后续步骤:"
echo " 1. 重启后端服务: docker restart cosmo-backend"
echo " 2. 登录系统验证菜单显示"
echo " 3. 测试用户功能"
echo ""
exit 0
else
print_error "升级失败(已自动回滚)"
show_rollback_info
exit 1
fi
}
main