灰度脚本
This commit is contained in:
25
scripts/manual_db_release/01_create_database.sql
Normal file
25
scripts/manual_db_release/01_create_database.sql
Normal file
@@ -0,0 +1,25 @@
|
||||
-- 生产数据库手工创建模板
|
||||
-- 用途:首次上线时手工创建数据库和应用账号
|
||||
-- 注意:执行前请先替换所有占位符
|
||||
--
|
||||
-- 占位符:
|
||||
-- __DB_NAME__ 生产数据库名
|
||||
-- __DB_USER__ 生产数据库用户名
|
||||
-- __DB_PASSWORD__ 生产数据库密码
|
||||
|
||||
-- 1. 创建应用数据库账号
|
||||
CREATE ROLE junhong_cmp
|
||||
LOGIN
|
||||
PASSWORD 'CtCom1zBzPQbpVNf3rCNxH';
|
||||
|
||||
-- 2. 创建生产数据库
|
||||
CREATE DATABASE junhong_cmp_prod
|
||||
OWNER junhong_cmp
|
||||
ENCODING 'UTF8'
|
||||
TEMPLATE template0;
|
||||
|
||||
-- 3. 授权
|
||||
GRANT ALL PRIVILEGES ON DATABASE junhong_cmp_prod TO junhong_cmp;
|
||||
|
||||
-- 4. 设置默认时区(与应用一致)
|
||||
ALTER DATABASE junhong_cmp_prod SET timezone TO 'Asia/Shanghai';
|
||||
76
scripts/manual_db_release/02_generate_schema_baseline.sh
Executable file
76
scripts/manual_db_release/02_generate_schema_baseline.sh
Executable file
@@ -0,0 +1,76 @@
|
||||
#!/bin/bash
|
||||
# 生成生产首发 schema 基线(只读,不修改源库)
|
||||
#
|
||||
# 用法:
|
||||
# SOURCE_DSN="postgres://user:pass@host:5432/db?sslmode=disable" \
|
||||
# OUTPUT_SQL="/tmp/00_schema_baseline.sql" \
|
||||
# bash scripts/manual_db_release/02_generate_schema_baseline.sh
|
||||
#
|
||||
# 可选:
|
||||
# EXTRA_EXCLUDE_TABLES="table_a,table_b"
|
||||
#
|
||||
# 默认排除:
|
||||
# - schema_migrations
|
||||
# - tb_data_usage_record
|
||||
# - tb_card_replacement_record_legacy
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
OUTPUT_SQL="${OUTPUT_SQL:-${SCRIPT_DIR}/generated/00_schema_baseline.sql}"
|
||||
|
||||
if ! command -v pg_dump >/dev/null 2>&1; then
|
||||
echo "错误:未找到 pg_dump,请先安装 PostgreSQL 客户端工具。"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "${SOURCE_DSN:-}" ]; then
|
||||
echo "错误:必须设置 SOURCE_DSN。"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p "$(dirname "${OUTPUT_SQL}")"
|
||||
|
||||
exclude_tables=(
|
||||
"schema_migrations"
|
||||
"tb_data_usage_record"
|
||||
"tb_card_replacement_record_legacy"
|
||||
)
|
||||
|
||||
if [ -n "${EXTRA_EXCLUDE_TABLES:-}" ]; then
|
||||
IFS=',' read -r -a extra_tables <<< "${EXTRA_EXCLUDE_TABLES}"
|
||||
for table_name in "${extra_tables[@]}"; do
|
||||
table_name="$(echo "${table_name}" | xargs)"
|
||||
if [ -n "${table_name}" ]; then
|
||||
exclude_tables+=("${table_name}")
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
pg_dump_args=(
|
||||
"--schema-only"
|
||||
"--no-owner"
|
||||
"--no-acl"
|
||||
"--quote-all-identifiers"
|
||||
)
|
||||
|
||||
for table_name in "${exclude_tables[@]}"; do
|
||||
pg_dump_args+=("--exclude-table=${table_name}")
|
||||
done
|
||||
|
||||
echo "开始生成 schema 基线:${OUTPUT_SQL}"
|
||||
pg_dump "${pg_dump_args[@]}" "${SOURCE_DSN}" > "${OUTPUT_SQL}"
|
||||
|
||||
echo ""
|
||||
echo "schema 基线生成完成。"
|
||||
echo "默认已排除以下对象:"
|
||||
for table_name in "${exclude_tables[@]}"; do
|
||||
echo " - ${table_name}"
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "建议你人工复核以下兼容保留表是否需要继续保留:"
|
||||
echo " - tb_card_replacement_request"
|
||||
echo " - tb_number_card"
|
||||
echo " - tb_payment_merchant_setting"
|
||||
echo " - tb_dev_capability_config"
|
||||
80
scripts/manual_db_release/03_export_base_data_from_source.sh
Executable file
80
scripts/manual_db_release/03_export_base_data_from_source.sh
Executable file
@@ -0,0 +1,80 @@
|
||||
#!/bin/bash
|
||||
# 从已确认的源库导出基础数据(只读,不修改源库)
|
||||
#
|
||||
# 用法:
|
||||
# SOURCE_DSN="postgres://user:pass@host:5432/db?sslmode=disable" \
|
||||
# bash scripts/manual_db_release/03_export_base_data_from_source.sh
|
||||
#
|
||||
# 如需导出敏感表:
|
||||
# SOURCE_DSN="..." INCLUDE_SENSITIVE=1 bash scripts/manual_db_release/03_export_base_data_from_source.sh
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
GENERATED_DIR="${SCRIPT_DIR}/generated"
|
||||
NON_SENSITIVE_DIR="${GENERATED_DIR}/non_sensitive"
|
||||
SENSITIVE_DIR="${GENERATED_DIR}/sensitive"
|
||||
|
||||
if ! command -v pg_dump >/dev/null 2>&1; then
|
||||
echo "错误:未找到 pg_dump,请先安装 PostgreSQL 客户端工具。"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "${SOURCE_DSN:-}" ]; then
|
||||
echo "错误:必须设置 SOURCE_DSN。"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p "${NON_SENSITIVE_DIR}" "${SENSITIVE_DIR}"
|
||||
|
||||
non_sensitive_tables=(
|
||||
"tb_permission"
|
||||
"tb_role"
|
||||
"tb_role_permission"
|
||||
"tb_carrier"
|
||||
"tb_commission_withdrawal_setting"
|
||||
"tb_polling_config"
|
||||
"tb_polling_concurrency_config"
|
||||
"tb_polling_alert_rule"
|
||||
"tb_data_cleanup_config"
|
||||
)
|
||||
|
||||
sensitive_tables=(
|
||||
"tb_wechat_config"
|
||||
)
|
||||
|
||||
dump_table() {
|
||||
local table_name="$1"
|
||||
local output_file="$2"
|
||||
|
||||
pg_dump \
|
||||
--data-only \
|
||||
--column-inserts \
|
||||
--no-owner \
|
||||
--no-acl \
|
||||
--quote-all-identifiers \
|
||||
--table="${table_name}" \
|
||||
"${SOURCE_DSN}" > "${output_file}"
|
||||
}
|
||||
|
||||
echo "开始导出非敏感基础数据..."
|
||||
for table_name in "${non_sensitive_tables[@]}"; do
|
||||
output_file="${NON_SENSITIVE_DIR}/${table_name}.sql"
|
||||
dump_table "${table_name}" "${output_file}"
|
||||
echo " 已导出: ${table_name}"
|
||||
done
|
||||
|
||||
if [ "${INCLUDE_SENSITIVE:-0}" = "1" ]; then
|
||||
echo "开始导出敏感基础数据..."
|
||||
for table_name in "${sensitive_tables[@]}"; do
|
||||
output_file="${SENSITIVE_DIR}/${table_name}.sql"
|
||||
dump_table "${table_name}" "${output_file}"
|
||||
echo " 已导出: ${table_name}"
|
||||
done
|
||||
else
|
||||
echo "未导出敏感表。若需导出 tb_wechat_config,请设置 INCLUDE_SENSITIVE=1。"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "导出完成,输出目录:${GENERATED_DIR}"
|
||||
echo "注意:generated 目录下的 SQL 可能包含敏感信息,请勿直接提交到 Git。"
|
||||
71
scripts/manual_db_release/04_import_base_data_into_target.sh
Executable file
71
scripts/manual_db_release/04_import_base_data_into_target.sh
Executable file
@@ -0,0 +1,71 @@
|
||||
#!/bin/bash
|
||||
# 将已导出的基础数据 SQL 导入目标库
|
||||
#
|
||||
# 用法:
|
||||
# TARGET_DSN="postgres://user:pass@host:5432/db?sslmode=disable" \
|
||||
# bash scripts/manual_db_release/04_import_base_data_into_target.sh
|
||||
#
|
||||
# 如需导入敏感表:
|
||||
# TARGET_DSN="..." INCLUDE_SENSITIVE=1 bash scripts/manual_db_release/04_import_base_data_into_target.sh
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
GENERATED_DIR="${SCRIPT_DIR}/generated"
|
||||
NON_SENSITIVE_DIR="${GENERATED_DIR}/non_sensitive"
|
||||
SENSITIVE_DIR="${GENERATED_DIR}/sensitive"
|
||||
|
||||
if ! command -v psql >/dev/null 2>&1; then
|
||||
echo "错误:未找到 psql,请先安装 PostgreSQL 客户端工具。"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "${TARGET_DSN:-}" ]; then
|
||||
echo "错误:必须设置 TARGET_DSN。"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
import_order=(
|
||||
"tb_permission"
|
||||
"tb_role"
|
||||
"tb_role_permission"
|
||||
"tb_carrier"
|
||||
"tb_commission_withdrawal_setting"
|
||||
"tb_polling_config"
|
||||
"tb_polling_concurrency_config"
|
||||
"tb_polling_alert_rule"
|
||||
"tb_data_cleanup_config"
|
||||
)
|
||||
|
||||
echo "开始导入非敏感基础数据..."
|
||||
for table_name in "${import_order[@]}"; do
|
||||
sql_file="${NON_SENSITIVE_DIR}/${table_name}.sql"
|
||||
if [ ! -f "${sql_file}" ]; then
|
||||
echo "错误:缺少导出文件 ${sql_file}"
|
||||
echo "请先执行 03_export_base_data_from_source.sh"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo " 导入: ${table_name}"
|
||||
psql "${TARGET_DSN}" -v ON_ERROR_STOP=1 -f "${sql_file}"
|
||||
done
|
||||
|
||||
if [ "${INCLUDE_SENSITIVE:-0}" = "1" ]; then
|
||||
sensitive_file="${SENSITIVE_DIR}/tb_wechat_config.sql"
|
||||
if [ ! -f "${sensitive_file}" ]; then
|
||||
echo "错误:缺少敏感导出文件 ${sensitive_file}"
|
||||
echo "请先使用 INCLUDE_SENSITIVE=1 执行 03_export_base_data_from_source.sh"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo " 导入: tb_wechat_config"
|
||||
psql "${TARGET_DSN}" -v ON_ERROR_STOP=1 -f "${sensitive_file}"
|
||||
else
|
||||
echo "未导入敏感表。若需导入 tb_wechat_config,请设置 INCLUDE_SENSITIVE=1。"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "基础数据导入完成。"
|
||||
echo "下一步请执行:"
|
||||
echo " 1. scripts/manual_db_release/05_repair_base_data_sequences.sql"
|
||||
echo " 2. scripts/manual_db_release/06_mark_schema_migrations.sql"
|
||||
62
scripts/manual_db_release/05_repair_base_data_sequences.sql
Normal file
62
scripts/manual_db_release/05_repair_base_data_sequences.sql
Normal file
@@ -0,0 +1,62 @@
|
||||
-- 修正基础数据导入后的自增序列
|
||||
-- 用途:避免显式插入 ID 后,后续新增数据仍从旧序列值开始
|
||||
|
||||
SELECT setval(
|
||||
pg_get_serial_sequence('"tb_permission"', 'id'),
|
||||
COALESCE((SELECT MAX(id) FROM tb_permission), 1),
|
||||
(SELECT COUNT(*) > 0 FROM tb_permission)
|
||||
);
|
||||
|
||||
SELECT setval(
|
||||
pg_get_serial_sequence('"tb_role"', 'id'),
|
||||
COALESCE((SELECT MAX(id) FROM tb_role), 1),
|
||||
(SELECT COUNT(*) > 0 FROM tb_role)
|
||||
);
|
||||
|
||||
SELECT setval(
|
||||
pg_get_serial_sequence('"tb_role_permission"', 'id'),
|
||||
COALESCE((SELECT MAX(id) FROM tb_role_permission), 1),
|
||||
(SELECT COUNT(*) > 0 FROM tb_role_permission)
|
||||
);
|
||||
|
||||
SELECT setval(
|
||||
pg_get_serial_sequence('"tb_carrier"', 'id'),
|
||||
COALESCE((SELECT MAX(id) FROM tb_carrier), 1),
|
||||
(SELECT COUNT(*) > 0 FROM tb_carrier)
|
||||
);
|
||||
|
||||
SELECT setval(
|
||||
pg_get_serial_sequence('"tb_wechat_config"', 'id'),
|
||||
COALESCE((SELECT MAX(id) FROM tb_wechat_config), 1),
|
||||
(SELECT COUNT(*) > 0 FROM tb_wechat_config)
|
||||
);
|
||||
|
||||
SELECT setval(
|
||||
pg_get_serial_sequence('"tb_commission_withdrawal_setting"', 'id'),
|
||||
COALESCE((SELECT MAX(id) FROM tb_commission_withdrawal_setting), 1),
|
||||
(SELECT COUNT(*) > 0 FROM tb_commission_withdrawal_setting)
|
||||
);
|
||||
|
||||
SELECT setval(
|
||||
pg_get_serial_sequence('"tb_polling_config"', 'id'),
|
||||
COALESCE((SELECT MAX(id) FROM tb_polling_config), 1),
|
||||
(SELECT COUNT(*) > 0 FROM tb_polling_config)
|
||||
);
|
||||
|
||||
SELECT setval(
|
||||
pg_get_serial_sequence('"tb_polling_concurrency_config"', 'id'),
|
||||
COALESCE((SELECT MAX(id) FROM tb_polling_concurrency_config), 1),
|
||||
(SELECT COUNT(*) > 0 FROM tb_polling_concurrency_config)
|
||||
);
|
||||
|
||||
SELECT setval(
|
||||
pg_get_serial_sequence('"tb_polling_alert_rule"', 'id'),
|
||||
COALESCE((SELECT MAX(id) FROM tb_polling_alert_rule), 1),
|
||||
(SELECT COUNT(*) > 0 FROM tb_polling_alert_rule)
|
||||
);
|
||||
|
||||
SELECT setval(
|
||||
pg_get_serial_sequence('"tb_data_cleanup_config"', 'id'),
|
||||
COALESCE((SELECT MAX(id) FROM tb_data_cleanup_config), 1),
|
||||
(SELECT COUNT(*) > 0 FROM tb_data_cleanup_config)
|
||||
);
|
||||
16
scripts/manual_db_release/06_mark_schema_migrations.sql
Normal file
16
scripts/manual_db_release/06_mark_schema_migrations.sql
Normal file
@@ -0,0 +1,16 @@
|
||||
-- 手工对齐 schema_migrations
|
||||
-- 场景:首次生产上线使用“手工 schema 基线”建表后,
|
||||
-- 需要告诉 golang-migrate 当前数据库已经处于哪个版本。
|
||||
--
|
||||
-- 当前仓库基线版本:140
|
||||
-- 如果你上线时仓库已新增 141+ 迁移,请同步修改此文件。
|
||||
|
||||
CREATE TABLE IF NOT EXISTS schema_migrations (
|
||||
version BIGINT NOT NULL PRIMARY KEY,
|
||||
dirty BOOLEAN NOT NULL
|
||||
);
|
||||
|
||||
TRUNCATE TABLE schema_migrations;
|
||||
|
||||
INSERT INTO schema_migrations (version, dirty)
|
||||
VALUES (140, FALSE);
|
||||
35
scripts/manual_db_release/07_verify_manual_release.sql
Normal file
35
scripts/manual_db_release/07_verify_manual_release.sql
Normal file
@@ -0,0 +1,35 @@
|
||||
-- 手工上线后的数据库校验脚本
|
||||
-- 用途:确认 schema 版本、核心基础数据、敏感配置是否已正确导入
|
||||
|
||||
SELECT version, dirty
|
||||
FROM schema_migrations;
|
||||
|
||||
SELECT 'tb_permission' AS table_name, COUNT(*) AS row_count FROM tb_permission
|
||||
UNION ALL
|
||||
SELECT 'tb_role', COUNT(*) FROM tb_role
|
||||
UNION ALL
|
||||
SELECT 'tb_role_permission', COUNT(*) FROM tb_role_permission
|
||||
UNION ALL
|
||||
SELECT 'tb_carrier', COUNT(*) FROM tb_carrier
|
||||
UNION ALL
|
||||
SELECT 'tb_commission_withdrawal_setting', COUNT(*) FROM tb_commission_withdrawal_setting
|
||||
UNION ALL
|
||||
SELECT 'tb_polling_config', COUNT(*) FROM tb_polling_config
|
||||
UNION ALL
|
||||
SELECT 'tb_polling_concurrency_config', COUNT(*) FROM tb_polling_concurrency_config
|
||||
UNION ALL
|
||||
SELECT 'tb_polling_alert_rule', COUNT(*) FROM tb_polling_alert_rule
|
||||
UNION ALL
|
||||
SELECT 'tb_data_cleanup_config', COUNT(*) FROM tb_data_cleanup_config
|
||||
UNION ALL
|
||||
SELECT 'tb_wechat_config', COUNT(*) FROM tb_wechat_config;
|
||||
|
||||
SELECT table_name
|
||||
FROM information_schema.tables
|
||||
WHERE table_schema = 'public'
|
||||
AND table_name IN ('tb_data_usage_record', 'tb_card_replacement_record_legacy')
|
||||
ORDER BY table_name;
|
||||
|
||||
SELECT COUNT(*) AS super_admin_count
|
||||
FROM tb_account
|
||||
WHERE user_type = 1;
|
||||
2
scripts/manual_db_release/generated/.gitignore
vendored
Normal file
2
scripts/manual_db_release/generated/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
*
|
||||
!.gitignore
|
||||
Reference in New Issue
Block a user