QAUP_Management/deploy/docker/postgres/db-manager.sh

650 lines
18 KiB
Bash
Raw 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
# QAUP 数据库管理脚本
# 统一管理数据库相关的所有操作:导出、导入、备份、恢复、健康检查等
set -e
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
# 默认配置
DB_HOST=${DB_HOST:-localhost}
DB_PORT=${DB_PORT:-5432}
DB_NAME=${DB_NAME:-qaup}
DB_USER=${DB_USER:-postgres}
EXPORT_DIR=${EXPORT_DIR:-$SCRIPT_DIR/export}
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
print_message() {
local color=$1
local message=$2
echo -e "${color}${message}${NC}"
}
# 显示帮助信息
show_help() {
echo "QAUP 数据库管理脚本"
echo ""
echo "用法: $0 <命令> [选项]"
echo ""
echo "数据管理命令:"
echo " prepare-default 准备默认初始数据"
echo " prepare-export 从现有数据库导出并准备数据"
echo " prepare-custom 自定义数据组合"
echo " prepare-status 显示数据文件状态"
echo " prepare-clean 清理数据文件"
echo ""
echo "导出命令:"
echo " export-all 导出完整数据库"
echo " export-schema 仅导出表结构"
echo " export-data 仅导出数据"
echo " export-initial 导出分层初始数据(推荐)"
echo ""
echo "备份恢复命令:"
echo " backup 备份数据库"
echo " restore <file> 恢复数据库"
echo ""
echo "维护命令:"
echo " health 健康检查"
echo " test-connection 测试数据库连接"
echo ""
echo "环境变量:"
echo " DB_HOST 数据库主机默认localhost"
echo " DB_PORT 数据库端口默认5432"
echo " DB_NAME 数据库名称默认qaup"
echo " DB_USER 数据库用户默认postgres"
echo " EXPORT_DIR 导出目录(默认:./export"
echo ""
echo "示例:"
echo " $0 prepare-default # 准备默认数据"
echo " $0 prepare-export # 从现有系统导出数据"
echo " $0 export-initial # 导出分层初始数据"
echo " $0 backup # 备份数据库"
echo " $0 health # 健康检查"
}
# ==========================================
# 数据准备功能
# ==========================================
# 显示数据文件状态
show_data_status() {
print_message $BLUE "当前数据文件状态:"
echo ""
local files=(
"initial_data.sql:实际使用的初始数据"
"initial_data.template.sql:默认数据模板"
"01_system_data.sql:系统配置数据"
"02_business_data.sql:业务基础数据"
"03_sample_data.sql:示例数据"
)
for file_info in "${files[@]}"; do
local file="${file_info%%:*}"
local desc="${file_info##*:}"
local path="$SCRIPT_DIR/$file"
if [ -f "$path" ]; then
local size=$(du -h "$path" | cut -f1)
local lines=$(wc -l < "$path")
printf " %-25s %s %8s %6s 行 - %s\n" "$file" "✓" "$size" "$lines" "$desc"
else
printf " %-25s %s %8s %6s - %s\n" "$file" "✗" "-" "-" "$desc"
fi
done
echo ""
if [ -f "$SCRIPT_DIR/initial_data.sql" ]; then
print_message $GREEN "部署时将使用: initial_data.sql"
else
print_message $YELLOW "部署时将按顺序使用分层数据文件"
fi
}
# 准备默认数据
prepare_default_data() {
print_message $BLUE "准备默认模板数据..."
if [ ! -f "$SCRIPT_DIR/initial_data.template.sql" ]; then
print_message $RED "错误: 默认模板文件不存在"
exit 1
fi
cp "$SCRIPT_DIR/initial_data.template.sql" "$SCRIPT_DIR/initial_data.sql"
print_message $GREEN "✓ 已准备默认数据"
print_message $YELLOW "默认管理员账号: admin"
print_message $YELLOW "默认管理员密码: admin123"
}
# 从现有数据库导出并准备数据
prepare_export_data() {
print_message $BLUE "从现有数据库导出数据..."
# 检查连接参数
if [ -z "$DB_HOST" ] || [ -z "$DB_NAME" ] || [ -z "$DB_USER" ]; then
print_message $YELLOW "请设置数据库连接环境变量或使用默认值"
echo "当前设置:"
echo " DB_HOST=$DB_HOST"
echo " DB_PORT=$DB_PORT"
echo " DB_NAME=$DB_NAME"
echo " DB_USER=$DB_USER"
echo ""
read -p "是否继续? (y/N): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
exit 1
fi
fi
# 测试连接
test_database_connection
# 导出分层数据
export_initial_data
# 使用导出的完整数据
if [ -f "$EXPORT_DIR/initial_data_complete.sql" ]; then
cp "$EXPORT_DIR/initial_data_complete.sql" "$SCRIPT_DIR/initial_data.sql"
print_message $GREEN "✓ 已导出并准备完整初始数据"
else
print_message $RED "错误: 导出失败"
exit 1
fi
}
# 自定义数据组合
prepare_custom_data() {
print_message $BLUE "自定义数据组合..."
local system_data="$SCRIPT_DIR/01_system_data.sql"
local business_data="$SCRIPT_DIR/02_business_data.sql"
local sample_data="$SCRIPT_DIR/03_sample_data.sql"
if [ ! -f "$system_data" ]; then
print_message $RED "错误: 未找到系统数据文件,请先导出数据"
print_message $YELLOW "提示: $0 export-initial"
exit 1
fi
echo "请选择要包含的数据类型:"
echo "1. 系统配置数据 (必需) ✓"
echo "2. 业务基础数据"
echo "3. 示例数据"
echo ""
local include_business=false
local include_sample=false
if [ -f "$business_data" ]; then
read -p "是否包含业务基础数据? (Y/n): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Nn]$ ]]; then
include_business=true
fi
fi
if [ -f "$sample_data" ]; then
read -p "是否包含示例数据? (y/N): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
include_sample=true
fi
fi
# 生成自定义数据文件
local output_file="$SCRIPT_DIR/initial_data.sql"
cat > "$output_file" << 'EOF'
-- QAUP 自定义初始数据组合
-- 此文件由 db-manager.sh 自动生成
EOF
# 添加系统数据
echo "-- 系统基础配置数据" >> "$output_file"
cat "$system_data" >> "$output_file"
print_message $GREEN "✓ 已包含系统配置数据"
# 添加业务数据
if [ "$include_business" = true ] && [ -f "$business_data" ]; then
echo "-- 业务基础数据" >> "$output_file"
cat "$business_data" >> "$output_file"
print_message $GREEN "✓ 已包含业务基础数据"
fi
# 添加示例数据
if [ "$include_sample" = true ] && [ -f "$sample_data" ]; then
echo "-- 示例数据" >> "$output_file"
cat "$sample_data" >> "$output_file"
print_message $GREEN "✓ 已包含示例数据"
fi
print_message $GREEN "✓ 自定义数据组合完成"
}
# 清理数据文件
clean_data_files() {
print_message $YELLOW "清理数据文件..."
read -p "确定要清理所有数据文件吗? (y/N): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
return
fi
local files_to_clean=(
"initial_data.sql"
"01_system_data.sql"
"02_business_data.sql"
"03_sample_data.sql"
)
for file in "${files_to_clean[@]}"; do
local path="$SCRIPT_DIR/$file"
if [ -f "$path" ]; then
rm "$path"
print_message $GREEN "✓ 已删除 $file"
fi
done
if [ -d "$EXPORT_DIR" ]; then
rm -rf "$EXPORT_DIR"
print_message $GREEN "✓ 已清理导出目录"
fi
}
# ==========================================
# 数据导出功能
# ==========================================
# 测试数据库连接
test_database_connection() {
print_message $BLUE "测试数据库连接..."
if command -v pg_isready &> /dev/null; then
if pg_isready -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$DB_NAME" &>/dev/null; then
print_message $GREEN "✓ 数据库连接成功"
else
print_message $RED "✗ 数据库连接失败"
exit 1
fi
else
print_message $YELLOW "警告: pg_isready 不可用,跳过连接测试"
fi
}
# 导出完整数据库
export_all_data() {
print_message $BLUE "导出完整数据库..."
test_database_connection
mkdir -p "$EXPORT_DIR"
local output_file="$EXPORT_DIR/qaup_complete_backup.sql"
pg_dump -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$DB_NAME" \
--no-owner --no-privileges --clean --if-exists \
> "$output_file"
print_message $GREEN "✓ 完整数据库导出完成: $output_file"
}
# 导出表结构
export_schema_only() {
print_message $BLUE "导出数据库表结构..."
test_database_connection
mkdir -p "$EXPORT_DIR"
local output_file="$EXPORT_DIR/qaup_database_schema.sql"
pg_dump -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$DB_NAME" \
--schema-only --no-owner --no-privileges --clean --if-exists \
> "$output_file"
print_message $GREEN "✓ 表结构导出完成: $output_file"
}
# 导出分层初始数据
export_initial_data() {
print_message $BLUE "导出分层初始数据..."
test_database_connection
mkdir -p "$EXPORT_DIR"
# 导出系统基础数据
export_system_data
# 导出业务基础数据
export_business_data
# 导出示例数据
export_sample_data
# 生成合并文件
generate_combined_data
}
# 导出系统基础数据
export_system_data() {
local output_file="$EXPORT_DIR/01_system_data.sql"
local system_tables=(
"sys_config" "sys_dict_type" "sys_dict_data" "sys_dept" "sys_post"
"sys_role" "sys_menu" "sys_user" "sys_user_role" "sys_user_post"
"sys_role_menu" "sys_role_dept" "sys_notice"
)
local table_args=""
for table in "${system_tables[@]}"; do
table_args="$table_args --table=$table"
done
cat > "$output_file" << 'EOF'
-- QAUP 系统基础配置数据
SET session_replication_role = replica;
EOF
pg_dump -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$DB_NAME" \
--data-only --no-owner --no-privileges --disable-triggers --inserts \
$table_args >> "$output_file"
cat >> "$output_file" << 'EOF'
SET session_replication_role = DEFAULT;
EOF
print_message $GREEN "✓ 系统基础数据导出完成"
}
# 导出业务基础数据
export_business_data() {
local output_file="$EXPORT_DIR/02_business_data.sql"
local business_tables=(
"sys_vehicle_type" "airport_areas" "spatial_rules"
"spatial_rule_vehicle_types" "transport_routes"
)
local table_args=""
for table in "${business_tables[@]}"; do
table_args="$table_args --table=$table"
done
cat > "$output_file" << 'EOF'
-- QAUP 业务基础数据
SET session_replication_role = replica;
EOF
pg_dump -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$DB_NAME" \
--data-only --no-owner --no-privileges --disable-triggers --inserts \
$table_args >> "$output_file" 2>/dev/null || true
cat >> "$output_file" << 'EOF'
SET session_replication_role = DEFAULT;
EOF
print_message $GREEN "✓ 业务基础数据导出完成"
}
# 导出示例数据
export_sample_data() {
local output_file="$EXPORT_DIR/03_sample_data.sql"
local sample_tables=("sys_vehicle_info")
local table_args=""
for table in "${sample_tables[@]}"; do
table_args="$table_args --table=$table"
done
cat > "$output_file" << 'EOF'
-- QAUP 示例数据
SET session_replication_role = replica;
EOF
pg_dump -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$DB_NAME" \
--data-only --no-owner --no-privileges --disable-triggers --inserts \
$table_args >> "$output_file" 2>/dev/null || true
cat >> "$output_file" << 'EOF'
SET session_replication_role = DEFAULT;
EOF
print_message $GREEN "✓ 示例数据导出完成"
}
# 生成合并的完整数据文件
generate_combined_data() {
local combined_file="$EXPORT_DIR/initial_data_complete.sql"
cat > "$combined_file" << 'EOF'
-- QAUP 系统完整初始数据
-- 此文件由 db-manager.sh 自动生成
EOF
for data_file in "01_system_data.sql" "02_business_data.sql" "03_sample_data.sql"; do
if [ -f "$EXPORT_DIR/$data_file" ]; then
cat "$EXPORT_DIR/$data_file" >> "$combined_file"
echo "" >> "$combined_file"
fi
done
print_message $GREEN "✓ 完整初始数据文件生成完成: $combined_file"
}
# ==========================================
# 备份恢复功能
# ==========================================
# 备份数据库
backup_database() {
print_message $BLUE "备份数据库..."
local timestamp=$(date +%Y%m%d_%H%M%S)
local backup_dir="$PROJECT_ROOT/backup/postgres"
local backup_file="$backup_dir/qaup_backup_$timestamp.sql"
mkdir -p "$backup_dir"
# 检查是否在容器内
if [ -f "/.dockerenv" ]; then
# 在容器内执行备份
pg_dump -U "$POSTGRES_USER" -d "$POSTGRES_DB" \
--no-owner --no-privileges > "$backup_file"
else
# 在容器外执行备份
test_database_connection
pg_dump -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$DB_NAME" \
--no-owner --no-privileges > "$backup_file"
fi
print_message $GREEN "✓ 数据库备份完成: $backup_file"
}
# 恢复数据库
restore_database() {
local backup_file=$1
if [ -z "$backup_file" ]; then
print_message $RED "错误: 请指定备份文件"
exit 1
fi
if [ ! -f "$backup_file" ]; then
print_message $RED "错误: 备份文件不存在: $backup_file"
exit 1
fi
print_message $BLUE "恢复数据库..."
print_message $YELLOW "警告: 这将覆盖现有数据"
read -p "确定要继续吗? (y/N): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
exit 1
fi
# 检查是否在容器内
if [ -f "/.dockerenv" ]; then
# 在容器内执行恢复
psql -U "$POSTGRES_USER" -d "$POSTGRES_DB" -f "$backup_file"
else
# 在容器外执行恢复
test_database_connection
psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$DB_NAME" -f "$backup_file"
fi
print_message $GREEN "✓ 数据库恢复完成"
}
# ==========================================
# 健康检查功能
# ==========================================
# 健康检查
health_check() {
print_message $BLUE "数据库健康检查..."
# 检查是否在容器内
if [ -f "/.dockerenv" ]; then
# 容器内健康检查
container_health_check
else
# 容器外健康检查
external_health_check
fi
}
# 容器内健康检查
container_health_check() {
local errors=0
# 检查 PostgreSQL 进程
if pgrep -x postgres > /dev/null; then
print_message $GREEN "✓ PostgreSQL 进程运行正常"
else
print_message $RED "✗ PostgreSQL 进程未运行"
errors=$((errors + 1))
fi
# 检查数据库连接
if psql -U "$POSTGRES_USER" -d "$POSTGRES_DB" -c "SELECT 1;" > /dev/null 2>&1; then
print_message $GREEN "✓ 数据库连接正常"
else
print_message $RED "✗ 数据库连接失败"
errors=$((errors + 1))
fi
# 检查表数量
local table_count=$(psql -U "$POSTGRES_USER" -d "$POSTGRES_DB" -t -c "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = 'public';" 2>/dev/null | tr -d ' ')
if [ "$table_count" -gt 0 ]; then
print_message $GREEN "✓ 数据库包含 $table_count 个表"
else
print_message $RED "✗ 数据库中没有表"
errors=$((errors + 1))
fi
if [ $errors -eq 0 ]; then
print_message $GREEN "数据库健康检查通过"
else
print_message $RED "数据库健康检查失败,发现 $errors 个问题"
exit 1
fi
}
# 容器外健康检查
external_health_check() {
test_database_connection
# 检查表数量
local table_count=$(psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$DB_NAME" -t -c "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = 'public';" 2>/dev/null | tr -d ' ')
if [ "$table_count" -gt 0 ]; then
print_message $GREEN "✓ 数据库包含 $table_count 个表"
else
print_message $RED "✗ 数据库中没有表"
exit 1
fi
print_message $GREEN "数据库健康检查通过"
}
# ==========================================
# 主函数
# ==========================================
main() {
if [ $# -eq 0 ]; then
show_help
exit 0
fi
local command=$1
shift
case $command in
# 数据准备命令
prepare-default)
prepare_default_data
;;
prepare-export)
prepare_export_data
;;
prepare-custom)
prepare_custom_data
;;
prepare-status)
show_data_status
;;
prepare-clean)
clean_data_files
;;
# 导出命令
export-all)
export_all_data
;;
export-schema)
export_schema_only
;;
export-initial)
export_initial_data
;;
# 备份恢复命令
backup)
backup_database
;;
restore)
restore_database "$@"
;;
# 维护命令
health)
health_check
;;
test-connection)
test_database_connection
;;
# 帮助
help|--help|-h)
show_help
;;
*)
print_message $RED "未知命令: $command"
show_help
exit 1
;;
esac
}
main "$@"