MySQL全量备份+还原脚本

  |   0 评论   |   0 浏览

1、创建mysql_backup.sh备份脚本如下:

#!/bin/bash
# ==============================================================================
# MySQL 8.0 全量备份脚本
# ==============================================================================

# -------------------------- 1. 核心配置(必须修改!)--------------------------
MYSQL_BIN_DIR="/usr/local/mysql-8.0.29/bin"  # MySQL的bin目录绝对路径(包含mysqldump的目录)
MYSQL_USER="root"            # 备份用户
MYSQL_PASS=""         # 备份用户密码
MYSQL_HOST="127.0.0.1"              # 数据库地址
MYSQL_PORT="3306"                   # 数据库端口
BACKUP_DB="all"                     # "all" 或指定库(如 "db1 db2")
BACKUP_DIR="/data/backups/mysql"    # 备份文件存储目录
RETENTION_DAYS=7                    # 备份保留天数
LOG_FILE="${BACKUP_DIR}/mysql8_backup.log"


# -------------------------- 2. 工具路径定义 --------------------------
MYSQL_DUMP="${MYSQL_BIN_DIR}/mysqldump"
MYSQL_CMD="${MYSQL_BIN_DIR}/mysql"
TAR_CMD="tar"  # tar命令路径,通常在默认环境变量中


# -------------------------- 3. 前置检查 --------------------------
# 检查MySQL bin目录
if [ ! -d "${MYSQL_BIN_DIR}" ]; then
    echo "[$(date +'%Y-%m-%d %H:%M:%S')] 错误:MySQL bin目录 ${MYSQL_BIN_DIR} 不存在!" >> ${LOG_FILE}
    exit 1
fi

# 检查mysqldump
if [ ! -f "${MYSQL_DUMP}" ]; then
    echo "[$(date +'%Y-%m-%d %H:%M:%S')] 错误:未找到 mysqldump 工具!" >> ${LOG_FILE}
    exit 1
fi

# 检查tar命令
if ! command -v ${TAR_CMD} &> /dev/null; then
    echo "[$(date +'%Y-%m-%d %H:%M:%S')] 错误:未找到 tar 命令,无法创建压缩文件!" >> ${LOG_FILE}
    exit 1
fi

# 创建备份目录
if [ ! -d "${BACKUP_DIR}" ]; then
    mkdir -p "${BACKUP_DIR}"
    echo "[$(date +'%Y-%m-%d %H:%M:%S')] 提示:创建备份目录 ${BACKUP_DIR}" >> ${LOG_FILE}
fi


# -------------------------- 4. 获取需要备份的数据库列表 --------------------------
# 定义需要排除的系统库
SYSTEM_DBS=("information_schema" "performance_schema" "sys" "mysql")

if [ "${BACKUP_DB}" = "all" ]; then
    # 获取所有数据库,排除系统库
    ALL_DBS=$(${MYSQL_CMD} -u${MYSQL_USER} -p${MYSQL_PASS} -h${MYSQL_HOST} -P${MYSQL_PORT} \
        -Nse "SELECT SCHEMA_NAME FROM information_schema.SCHEMATA")
    # 过滤系统库
    BACKUP_DBS=()
    for db in ${ALL_DBS}; do
        if ! [[ " ${SYSTEM_DBS[@]} " =~ " ${db} " ]]; then
            BACKUP_DBS+=("${db}")
        fi
    done
else
    # 使用指定的数据库列表
    BACKUP_DBS=(${BACKUP_DB})
fi

# 检查是否有需要备份的数据库
if [ ${#BACKUP_DBS[@]} -eq 0 ]; then
    echo "[$(date +'%Y-%m-%d %H:%M:%S')] 警告:没有需要备份的数据库!" >> ${LOG_FILE}
    exit 0
fi


# -------------------------- 5. 逐个备份数据库并生成tar.gz文件 --------------------------
BACKUP_TIME=$(date +'%Y%m%d_%H%M%S')  # 统一时间戳,便于识别同一批次备份

for db in "${BACKUP_DBS[@]}"; do
    echo "[$(date +'%Y-%m-%d %H:%M:%S')] 开始备份数据库:${db}" >> ${LOG_FILE}
  
    # 临时SQL文件名
    TEMP_SQL="${BACKUP_DIR}/${db}_${BACKUP_TIME}.sql"
    # 最终tar.gz文件名
    TAR_FILE="${BACKUP_DIR}/${db}_${BACKUP_TIME}.tar.gz"
  
    # 备份数据库到SQL文件
    ${MYSQL_DUMP} -u${MYSQL_USER} -p${MYSQL_PASS} -h${MYSQL_HOST} -P${MYSQL_PORT} \
        --databases ${db} \
        --column-statistics=0 \
        > ${TEMP_SQL}
  
    # 检查SQL文件是否生成成功
    if [ $? -ne 0 ] || [ ! -s "${TEMP_SQL}" ]; then
        echo "[$(date +'%Y-%m-%d %H:%M:%S')] 失败:数据库 ${db} 备份失败!" >> ${LOG_FILE}
        rm -f ${TEMP_SQL}  # 清理失败的临时文件
        continue
    fi
  
    # 将SQL文件压缩为tar.gz
    ${TAR_CMD} -zcf ${TAR_FILE} -C ${BACKUP_DIR} ${db}_${BACKUP_TIME}.sql
  
    # 检查压缩文件
    if [ $? -eq 0 ] && [ -s "${TAR_FILE}" ]; then
        rm -f ${TEMP_SQL}  # 压缩成功后删除临时SQL文件
        echo "[$(date +'%Y-%m-%d %H:%M:%S')] 成功:数据库 ${db} 备份完成 -> ${TAR_FILE}" >> ${LOG_FILE}
    else
        echo "[$(date +'%Y-%m-%d %H:%M:%S')] 失败:数据库 ${db} 压缩失败!" >> ${LOG_FILE}
        rm -f ${TEMP_SQL} ${TAR_FILE}  # 清理失败文件
    fi
done


# -------------------------- 6. 清理过期备份 --------------------------
echo "[$(date +'%Y-%m-%d %H:%M:%S')] 开始清理 ${RETENTION_DAYS} 天前的备份文件..." >> ${LOG_FILE}
find ${BACKUP_DIR} -name "*.tar.gz" -mtime +${RETENTION_DAYS} -delete

if [ $? -eq 0 ]; then
    echo "[$(date +'%Y-%m-%d %H:%M:%S')] 成功:过期备份清理完成" >> ${LOG_FILE}
else
    echo "[$(date +'%Y-%m-%d %H:%M:%S')] 警告:过期备份清理可能存在问题!" >> ${LOG_FILE}
fi

echo "===============================数据库备份完成=======================================" >> ${LOG_FILE}

2、创建mysql_restore.sh还原脚本如下:

#!/bin/bash
# ==============================================================================
# MySQL 数据库还原脚本
# ==============================================================================

# -------------------------- 1. 配置参数(必须修改!)--------------------------
MYSQL_BIN_DIR="/usr/local/mysql-8.0.43/bin"  # MySQL的bin目录(包含mysql命令)
MYSQL_USER="root"                   # 具有还原权限的用户(建议用root)
MYSQL_PASS=""                       # 对应用户的密码(若含特殊符号,需用单引号包裹)
MYSQL_HOST="127.0.0.1"              # 数据库地址
MYSQL_PORT="3306"                   # 数据库端口
BACKUP_DIR="/data/backups/mysql"     # 备份文件所在目录(与备份脚本一致)
TEMP_DIR="${BACKUP_DIR}/temp_restore"  # 临时解压目录(自动创建和清理)
# 日志文件路径:备份目录下,格式「mysql_restore_20240826.log」
LOG_FILE="${BACKUP_DIR}/mysql_restore_$(date +%Y%m%d).log"


# -------------------------- 2. 日志函数与前置初始化 --------------------------
# 日志输出函数:参数1=日志级别(INFO/ERROR/WARN),参数2=日志内容
log() {
    local LEVEL=$1
    local MESSAGE=$2
    local TIMESTAMP=$(date +"%Y-%m-%d %H:%M:%S")
    # 输出到控制台(区分颜色,可选)
    case ${LEVEL} in
        INFO) echo -e "\033[32m[${TIMESTAMP}] [INFO] ${MESSAGE}\033[0m" ;;
        ERROR) echo -e "\033[31m[${TIMESTAMP}] [ERROR] ${MESSAGE}\033[0m" ;;
        WARN) echo -e "\033[33m[${TIMESTAMP}] [WARN] ${MESSAGE}\033[0m" ;;
    esac
    # 写入日志文件(无颜色,仅文本)
    echo "[${TIMESTAMP}] [${LEVEL}] ${MESSAGE}" >> "${LOG_FILE}"
}

# 工具路径定义
MYSQL_CMD="${MYSQL_BIN_DIR}/mysql"
TAR_CMD="tar"

# 脚本启动日志(记录基础配置)
log "INFO" "==================== MySQL 还原脚本启动 ===================="
log "INFO" "脚本执行时间:$(date +"%Y-%m-%d %H:%M:%S")"
log "INFO" "MySQL 配置:用户=${MYSQL_USER},主机=${MYSQL_HOST},端口=${MYSQL_PORT}"
log "INFO" "备份目录:${BACKUP_DIR}"
log "INFO" "临时目录:${TEMP_DIR}"
log "INFO" "日志文件:${LOG_FILE}"


# -------------------------- 3. 前置检查(带日志)--------------------------
# 检查MySQL命令是否存在
if [ ! -f "${MYSQL_CMD}" ]; then
    log "ERROR" "未找到mysql命令,路径:${MYSQL_CMD}"
    rm -rf "${TEMP_DIR}"
    exit 1
fi

# 检查tar命令
if ! command -v ${TAR_CMD} &> /dev/null; then
    log "ERROR" "未找到tar命令,无法解压备份文件"
    rm -rf "${TEMP_DIR}"
    exit 1
fi

# 检查备份目录是否存在
if [ ! -d "${BACKUP_DIR}" ]; then
    log "ERROR" "备份目录 ${BACKUP_DIR} 不存在"
    rm -rf "${TEMP_DIR}"
    exit 1
fi

# 创建临时解压目录
mkdir -p "${TEMP_DIR}"
if [ $? -ne 0 ]; then
    log "ERROR" "无法创建临时目录 ${TEMP_DIR}"
    exit 1
fi
log "INFO" "临时目录 ${TEMP_DIR} 创建成功"


# -------------------------- 4. 选择还原模式 --------------------------
echo -e "\n请选择还原模式:" | tee -a "${LOG_FILE}"
echo "1) 还原单个数据库" | tee -a "${LOG_FILE}"
echo "2) 还原所有备份的数据库" | tee -a "${LOG_FILE}"
read -p "请输入选项 (1/2):" MODE

# 验证输入
if [ "${MODE}" != "1" ] && [ "${MODE}" != "2" ]; then
    log "ERROR" "无效选项【${MODE}】,请输入 1 或 2"
    rm -rf "${TEMP_DIR}"
    exit 1
fi
log "INFO" "已选择还原模式:${MODE}(1=单个数据库,2=所有数据库)"


# -------------------------- 5. 还原单个数据库 --------------------------
if [ "${MODE}" = "1" ]; then
    # 列出所有备份文件
    log "INFO" "开始列出备份目录中的 .tar.gz 文件"
    BACKUP_FILE_LIST=$(ls -1 "${BACKUP_DIR}"/*.tar.gz 2>/dev/null | grep -v "temp_restore")
  
    if [ -z "${BACKUP_FILE_LIST}" ]; then
        log "ERROR" "备份目录中未找到 .tar.gz 备份文件"
        rm -rf "${TEMP_DIR}"
        exit 1
    fi
  
    echo -e "\n备份目录中的文件:" | tee -a "${LOG_FILE}"
    echo "${BACKUP_FILE_LIST}" | tee -a "${LOG_FILE}"
    log "INFO" "备份目录共找到 $(echo "${BACKUP_FILE_LIST}" | wc -l) 个备份文件"
  
    # 输入要还原的文件名
    read -p "请输入要还原的文件名(含.tar.gz):" BACKUP_FILE
    FULL_PATH="${BACKUP_DIR}/${BACKUP_FILE}"
    log "INFO" "用户指定还原文件:${BACKUP_FILE}(完整路径:${FULL_PATH})"
  
    # 检查文件是否存在
    if [ ! -f "${FULL_PATH}" ]; then
        log "ERROR" "文件 ${FULL_PATH} 不存在"
        rm -rf "${TEMP_DIR}"
        exit 1
    fi
  
    # 提取数据库名(从文件名中解析,格式:数据库名_时间戳.tar.gz)
    DB_NAME=$(echo "${BACKUP_FILE}" | awk -F'_[0-9]{8}_[0-9]{6}\.tar\.gz$' '{print $1}')
    if [ -z "${DB_NAME}" ]; then
        log "ERROR" "无法从文件名【${BACKUP_FILE}】解析数据库名,请确认格式为「数据库名_YYYYMMDD_HHMMSS.tar.gz」"
        rm -rf "${TEMP_DIR}"
        exit 1
    fi
    log "INFO" "从文件名解析到数据库名:${DB_NAME}"
  
    # 解压备份文件
    log "INFO" "开始解压备份文件:${FULL_PATH},目标目录:${TEMP_DIR}"
    ${TAR_CMD} -zxf "${FULL_PATH}" -C "${TEMP_DIR}" 2>> "${LOG_FILE}"
    if [ $? -ne 0 ]; then
        log "ERROR" "解压备份文件【${FULL_PATH}】失败(详细错误见日志文件)"
        rm -rf "${TEMP_DIR}"
        exit 1
    fi
    log "INFO" "备份文件解压成功"
  
    # 找到解压后的SQL文件
    SQL_FILE=$(find "${TEMP_DIR}" -name "${DB_NAME}_*.sql" | head -n 1)
    if [ ! -f "${SQL_FILE}" ]; then
        log "ERROR" "在临时目录【${TEMP_DIR}】中未找到 ${DB_NAME}_*.sql 文件"
        rm -rf "${TEMP_DIR}"
        exit 1
    fi
    log "INFO" "找到解压后的SQL文件:${SQL_FILE}"
  
    # 创建数据库(如果不存在)
    log "INFO" "检查数据库 ${DB_NAME} 是否存在"
    # 处理MySQL密码含特殊符号的情况(用--password参数而非-p)
    DB_EXISTS=$(${MYSQL_CMD} -u"${MYSQL_USER}" --password="${MYSQL_PASS}" -h"${MYSQL_HOST}" -P"${MYSQL_PORT}" \
        -Nse "SELECT 1 FROM information_schema.SCHEMATA WHERE SCHEMA_NAME='${DB_NAME}'" 2>> "${LOG_FILE}")
  
    if [ -z "${DB_EXISTS}" ]; then
        log "INFO" "数据库 ${DB_NAME} 不存在,开始创建(字符集:utf8mb4,排序规则:utf8mb4_unicode_ci)"
        ${MYSQL_CMD} -u"${MYSQL_USER}" --password="${MYSQL_PASS}" -h"${MYSQL_HOST}" -P"${MYSQL_PORT}" \
            -e "CREATE DATABASE IF NOT EXISTS ${DB_NAME} CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci" 2>> "${LOG_FILE}"
        if [ $? -ne 0 ]; then
            log "ERROR" "创建数据库 ${DB_NAME} 失败(详细错误见日志文件)"
            rm -rf "${TEMP_DIR}"
            exit 1
        fi
        log "INFO" "数据库 ${DB_NAME} 创建成功"
    else
        log "INFO" "数据库 ${DB_NAME} 已存在,跳过创建步骤"
    fi
  
    # 执行还原
    log "INFO" "开始还原数据库 ${DB_NAME}(SQL文件:${SQL_FILE})"
    ${MYSQL_CMD} -u"${MYSQL_USER}" --password="${MYSQL_PASS}" -h"${MYSQL_HOST}" -P"${MYSQL_PORT}" \
        "${DB_NAME}" < "${SQL_FILE}" 2>> "${LOG_FILE}"
  
    if [ $? -eq 0 ]; then
        log "INFO" "成功:数据库 ${DB_NAME} 还原完成"
    else
        log "ERROR" "错误:数据库 ${DB_NAME} 还原失败(详细错误见日志文件)"
        rm -rf "${TEMP_DIR}"
        exit 1
    fi


# -------------------------- 6. 还原所有数据库 --------------------------
elif [ "${MODE}" = "2" ]; then
    # 获取所有备份文件(排除临时目录)
    BACKUP_FILES=$(ls -1 "${BACKUP_DIR}"/*.tar.gz 2>/dev/null | grep -v "temp_restore")
    if [ -z "${BACKUP_FILES}" ]; then
        log "ERROR" "备份目录中未找到 .tar.gz 备份文件"
        rm -rf "${TEMP_DIR}"
        exit 1
    fi
  
    FILE_COUNT=$(echo "${BACKUP_FILES}" | wc -l)
    log "INFO" "找到 ${FILE_COUNT} 个备份文件,将逐个还原"
    echo -e "\n找到的备份文件列表:" | tee -a "${LOG_FILE}"
    echo "${BACKUP_FILES}" | tee -a "${LOG_FILE}"
  
    # 逐个还原
    for FULL_PATH in ${BACKUP_FILES}; do
        # 提取文件名和数据库名
        BACKUP_FILE=$(basename "${FULL_PATH}")
        DB_NAME=$(echo "${BACKUP_FILE}" | awk -F'_[0-9]{8}_[0-9]{6}\.tar\.gz$' '{print $1}')
  
        log "INFO" "==================== 开始处理文件:${BACKUP_FILE} ===================="
  
        # 跳过无法解析数据库名的文件
        if [ -z "${DB_NAME}" ]; then
            log "WARN" "跳过文件【${BACKUP_FILE}】:无法解析数据库名(格式需为「数据库名_YYYYMMDD_HHMMSS.tar.gz」)"
            continue
        fi
        log "INFO" "解析到数据库名:${DB_NAME}"
  
        # 解压备份文件
        log "INFO" "开始解压文件:${FULL_PATH}"
        ${TAR_CMD} -zxf "${FULL_PATH}" -C "${TEMP_DIR}" 2>> "${LOG_FILE}"
        if [ $? -ne 0 ]; then
            log "WARN" "解压文件【${BACKUP_FILE}】失败,跳过该文件(详细错误见日志)"
            # 清理临时目录残留文件,避免影响下一个文件
            rm -rf "${TEMP_DIR}"/*
            continue
        fi
        log "INFO" "文件 ${BACKUP_FILE} 解压成功"
  
        # 找到SQL文件
        SQL_FILE=$(find "${TEMP_DIR}" -name "${DB_NAME}_*.sql" | head -n 1)
        if [ ! -f "${SQL_FILE}" ]; then
            log "WARN" "文件【${BACKUP_FILE}】解压后未找到 ${DB_NAME}_*.sql 文件,跳过"
            rm -rf "${TEMP_DIR}"/*
            continue
        fi
        log "INFO" "找到SQL文件:${SQL_FILE}"
  
        # 创建数据库(不存在则创建)
        log "INFO" "检查数据库 ${DB_NAME} 是否存在"
        DB_EXISTS=$(${MYSQL_CMD} -u"${MYSQL_USER}" --password="${MYSQL_PASS}" -h"${MYSQL_HOST}" -P"${MYSQL_PORT}" \
            -Nse "SELECT 1 FROM information_schema.SCHEMATA WHERE SCHEMA_NAME='${DB_NAME}'" 2>> "${LOG_FILE}")
  
        if [ -z "${DB_EXISTS}" ]; then
            log "INFO" "创建数据库 ${DB_NAME}(字符集:utf8mb4)"
            ${MYSQL_CMD} -u"${MYSQL_USER}" --password="${MYSQL_PASS}" -h"${MYSQL_HOST}" -P"${MYSQL_PORT}" \
                -e "CREATE DATABASE IF NOT EXISTS ${DB_NAME} CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci" 2>> "${LOG_FILE}"
            if [ $? -ne 0 ]; then
                log "WARN" "创建数据库 ${DB_NAME} 失败,跳过还原(详细错误见日志)"
                rm -rf "${TEMP_DIR}"/*
                continue
            fi
            log "INFO" "数据库 ${DB_NAME} 创建成功"
        else
            log "INFO" "数据库 ${DB_NAME} 已存在,跳过创建"
        fi
  
        # 执行还原
        log "INFO" "开始还原数据库 ${DB_NAME}"
        ${MYSQL_CMD} -u"${MYSQL_USER}" --password="${MYSQL_PASS}" -h"${MYSQL_HOST}" -P"${MYSQL_PORT}" \
            "${DB_NAME}" < "${SQL_FILE}" 2>> "${LOG_FILE}"
  
        if [ $? -eq 0 ]; then
            log "INFO" "成功:数据库 ${DB_NAME} 还原完成"
        else
            log "WARN" "失败:数据库 ${DB_NAME} 还原失败(详细错误见日志)"
        fi
  
        # 清理当前文件的临时解压内容,避免干扰下一个文件
        rm -rf "${TEMP_DIR}"/*
        log "INFO" "==================== 文件 ${BACKUP_FILE} 处理结束 ====================\n"
    done
  
    log "INFO" "所有备份文件处理完毕(共 ${FILE_COUNT} 个,具体结果见日志)"
fi


# -------------------------- 7. 清理与结束日志 --------------------------
log "INFO" "开始清理临时目录:${TEMP_DIR}"
rm -rf "${TEMP_DIR}"
if [ $? -eq 0 ]; then
    log "INFO" "临时目录清理成功"
else
    log "WARN" "临时目录 ${TEMP_DIR} 清理失败,请手动删除"
fi

log "INFO" "==================== MySQL 还原脚本执行结束 ====================\n"
echo -e "\n脚本执行结束,日志已保存至:${LOG_FILE}"


标题:MySQL全量备份+还原脚本
作者:zytops
地址:https://zytops.com/articles/2025/08/26/1756189317300.html