txw/devops/dump_mysql_schema.sh

160 lines
6.2 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.

#!/usr/bin/env bash
# ============================================================
# dump_mysql_schema.sh
# ------------------------------------------------------------
# 导出 MySQL 整库(或指定库)的纯 DDL 到 stdout。
# 目的:把线上生产数据库的"表结构"抓回来,与 docs/sql/init_database.sql 做 diff。
#
# 适用场景(任选其一):
# 1) 宿主机直接执行(远程 MySQL 同样可用,只要本机能连过去)
# 2) 容器内执行:
# docker exec -i txw-mysql bash -s < devops/dump_mysql_schema.sh \
# > prod_schema_$(date +%Y%m%d).sql
#
# 用法示例(远程库):
# MYSQL_HOST=192.168.110.55 MYSQL_PORT=3306 \
# MYSQL_USER=root MYSQL_PWD='your_password' \
# INCLUDE_DBS=qyd_txw \
# bash devops/dump_mysql_schema.sh > qyd_txw_schema_$(date +%Y%m%d).sql
#
# 可调环境变量(全部可选):
# MYSQL_HOST 远端/本机地址(默认 localhost
# MYSQL_PORT 端口(默认 3306
# MYSQL_USER 用户名(默认 root
# MYSQL_PWD 密码(推荐用单引号包裹,避免 $、! 等被 bash 解释)
# INCLUDE_DBS 只导指定库,多个用逗号分隔;留空=全部业务库
# EXCLUDE_DBS 排除的库默认information_schema,performance_schema,mysql,sys
# ============================================================
set -euo pipefail
# ---------- 默认值(与 devops/docker-compose.infra.prod.yml 保持一致) ----------
MYSQL_USER="${MYSQL_USER:-root}"
MYSQL_PWD="${MYSQL_PWD:-MysqlRootPwd@2024#Secure}"
MYSQL_HOST="${MYSQL_HOST:-localhost}"
MYSQL_PORT="${MYSQL_PORT:-3306}"
EXCLUDE_DBS="${EXCLUDE_DBS:-information_schema,performance_schema,mysql,sys}"
INCLUDE_DBS="${INCLUDE_DBS:-}"
# 容器内不落盘:所有 SQL 走 stdout 流到宿主机,容器内零残留。
# ---------- 工具自检 ----------
for bin in mysql mysqldump; do
if ! command -v "$bin" >/dev/null 2>&1; then
echo "[FATAL] 当前环境找不到 $bin,请先安装 mysql-clientapt: default-mysql-client / yum: mysql / dnf: mysql" >&2
exit 1
fi
done
# 把密码通过 MYSQL_PWD 环境变量传给客户端,避免命令行泄露
export MYSQL_PWD
log() { echo "[$(date '+%H:%M:%S')] $*" >&2; }
fail() { echo "[FATAL] $*" >&2; exit 1; }
# ---------- 1. 连通性自检 ----------
log "自检:尝试连接 ${MYSQL_USER}@${MYSQL_HOST}:${MYSQL_PORT} ..."
if ! mysql -h "$MYSQL_HOST" -P "$MYSQL_PORT" -u "$MYSQL_USER" \
-e "SELECT VERSION();" >/dev/null 2>&1; then
fail "无法连接 MySQL请检查账号/密码/网络"
fi
VERSION=$(mysql -h "$MYSQL_HOST" -P "$MYSQL_PORT" -u "$MYSQL_USER" -N -B \
-e "SELECT VERSION();" 2>/dev/null)
log "连接成功MySQL 版本: ${VERSION}"
# ---------- 2. 列出要导出的库 ----------
if [ -n "$INCLUDE_DBS" ]; then
# 把逗号分隔的 INCLUDE_DBS 变成 SQL IN (...) 列表
IN_CLAUSE=$(printf "%s" "$INCLUDE_DBS" | awk -F',' '{
out=""; for (i=1;i<=NF;i++){ gsub(/^ +| +$/,"",$i); out=out"'\''"$i"'\''," }
sub(/,$/,"",out); print out
}')
DB_LIST=$(mysql -h "$MYSQL_HOST" -P "$MYSQL_PORT" -u "$MYSQL_USER" -N -B -e \
"SELECT SCHEMA_NAME FROM information_schema.SCHEMATA
WHERE SCHEMA_NAME IN ($IN_CLAUSE) ORDER BY SCHEMA_NAME;" 2>/dev/null)
else
# 用 NOT REGEXP 排除系统库
EXCLUDED_REGEX=$(printf "%s" "$EXCLUDE_DBS" | sed 's/,/|/g')
DB_LIST=$(mysql -h "$MYSQL_HOST" -P "$MYSQL_PORT" -u "$MYSQL_USER" -N -B -e \
"SELECT SCHEMA_NAME FROM information_schema.SCHEMATA
WHERE SCHEMA_NAME NOT REGEXP '$EXCLUDED_REGEX'
ORDER BY SCHEMA_NAME;" 2>/dev/null)
fi
if [ -z "$DB_LIST" ]; then
fail "未找到任何目标库INCLUDE_DBS='${INCLUDE_DBS}', EXCLUDE_DBS='${EXCLUDE_DBS}'"
fi
log "将导出以下库: $(echo $DB_LIST | tr '\n' ' ')"
# ---------- 3. 写文件头(直写 stdout不落盘 ----------
echo "-- ============================================================"
echo "-- MySQL 整库 DDL 导出"
echo "-- 数据库版本: ${VERSION}"
echo "-- 生成时间 : $(date '+%Y-%m-%d %H:%M:%S %z')"
echo "-- 目标库 : $(echo $DB_LIST | tr '\n' ',' | sed 's/,$//')"
echo "-- 生成方式 : mysqldump --no-data仅结构不含数据"
echo "-- ============================================================"
echo "SET NAMES utf8mb4;"
echo "SET FOREIGN_KEY_CHECKS = 0;"
# ---------- 4. 逐库 dump直接 echo 到 stdout ----------
TOTAL_TABLES=0
TOTAL_VIEWS=0
for DB in $DB_LIST; do
log "==> 导出库 [$DB]"
echo ""
echo "-- ----------------------------"
echo "-- Database: ${DB}"
echo "-- ----------------------------"
echo "USE \`${DB}\`;"
# 取表列表
TABLES=$(mysql -h "$MYSQL_HOST" -P "$MYSQL_PORT" -u "$MYSQL_USER" -N -B -e \
"SELECT TABLE_NAME FROM information_schema.TABLES
WHERE TABLE_SCHEMA='${DB}' AND TABLE_TYPE='BASE TABLE'
ORDER BY TABLE_NAME;" 2>/dev/null)
for TBL in $TABLES; do
echo "DROP TABLE IF EXISTS \`${TBL}\`;"
mysqldump -h "$MYSQL_HOST" -P "$MYSQL_PORT" -u "$MYSQL_USER" \
--no-data --skip-comments --skip-add-locks \
--skip-lock-tables --skip-disable-keys \
--skip-tz-utc --set-gtid-purged=OFF \
--default-character-set=utf8mb4 \
--compact --skip-add-drop-table \
"${DB}" "${TBL}" 2>/dev/null
echo ";"
echo ""
TOTAL_TABLES=$((TOTAL_TABLES + 1))
done
# 取视图列表
VIEWS=$(mysql -h "$MYSQL_HOST" -P "$MYSQL_PORT" -u "$MYSQL_USER" -N -B -e \
"SELECT TABLE_NAME FROM information_schema.VIEWS
WHERE TABLE_SCHEMA='${DB}' ORDER BY TABLE_NAME;" 2>/dev/null || true)
for VW in $VIEWS; do
echo "DROP VIEW IF EXISTS \`${VW}\`;"
mysqldump -h "$MYSQL_HOST" -P "$MYSQL_PORT" -u "$MYSQL_USER" \
--no-data --skip-comments --skip-add-locks \
--skip-lock-tables --skip-disable-keys \
--set-gtid-purged=OFF \
--default-character-set=utf8mb4 \
--compact --skip-add-drop-table \
"${DB}" "${VW}" 2>/dev/null
echo ";"
echo ""
TOTAL_VIEWS=$((TOTAL_VIEWS + 1))
done
done
# ---------- 5. 文件尾 ----------
echo ""
echo "SET FOREIGN_KEY_CHECKS = 1;"
# 统计日志走 stderr不会污染 stdout 上的 SQL 文件
log "导出完成:表 ${TOTAL_TABLES} 个,视图 ${TOTAL_VIEWS}"