MySQL全量备份+还原脚本
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}"