一文分享MySQL数据库备份恢复脚本

 更新时间:2026年06月03日 09:06:24   作者:Oneslide  
在日常业务场景,通常情况下,我们不需要进行全库备份,而是只备份需要的数据库,本文分享一个MySQL数据库备份恢复脚本,用于备份和恢复指定的数据库,希望对大家有所帮助

本人亲测可用

在日常业务场景,通常情况下,我们不需要进行全库备份,而是只备份需要的数据库。本文分享一个MySQL数据库备份恢复脚本,用于备份和恢复指定的数据库。

备份脚本

#!/bin/bash
# MySQL 连接参数
MYSQL_HOST="127.0.0.1"
MYSQL_PORT="3306"
MYSQL_USER="root"
MYSQL_PASS='your_password'
# 备份目录
BACKUP_DIR="mysql-backup/$(date +%Y%m%d_%H%M%S)"
LOG_FILE="${BACKUP_DIR}/backup.log"
# 创建备份目录
mkdir -p "${BACKUP_DIR}"
# 日志函数
log() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "${LOG_FILE}"
}
# 开始备份
log "开始 MySQL 分表备份"
# 获取所有数据库列表(排除系统数据库)
# 检查是否提供了数据库参数
if [ $# -eq 0 ]; then
    echo "用法: $0 <数据库1> [数据库2] [数据库3] ..."
    echo "例如: $0 db1 db2 db3"
    exit 1
fi
# 指定的数据库列表
DATABASES=("$@")
# 验证指定的数据库是否存在
for DB in "${DATABASES[@]}"; do
    # 检查数据库是否存在
    DB_EXISTS=$(mysql -h "${MYSQL_HOST}" -P "${MYSQL_PORT}" -u "${MYSQL_USER}" -p${MYSQL_PASS} \
        -e "SHOW DATABASES LIKE '${DB}';" -s --skip-column-names)
    if [ -n "$DB_EXISTS" ]; then
        log "[INFO]数据库存在: $DB"
    else
        log "[ERROR]: 数据库 '$DB' 不存在,跳过"
        exit 1
    fi
done
if [ $? -ne 0 ]; then
    log "错误: 无法连接到 MySQL 服务器或获取数据库列表"
    exit 1
fi
log "找到数据库: $(echo ${DATABASES} | tr '\n' ' ')"
# 遍历每个数据库
for DB in ${DATABASES[@]}; do
    log "正在处理数据库: ${DB}"
    # 创建数据库目录
    DB_DIR="${BACKUP_DIR}/${DB}"
    mkdir -p "${DB_DIR}"
    # 获取数据库中的所有表
    TABLES=$(mysql -h "${MYSQL_HOST}" -P "${MYSQL_PORT}" -u "${MYSQL_USER}" -p${MYSQL_PASS} \
        -e "SHOW TABLES FROM \`${DB}\`;" -s --skip-column-names)
    if [ $? -ne 0 ]; then
        log "错误: 无法获取数据库 ${DB} 的表列表"
        continue
    fi
    log "数据库 ${DB} 中找到表: $(echo ${TABLES} | tr '\n' ' ')"
    # 遍历每个表进行备份
    for TABLE in ${TABLES}; do
        log "正在备份表: ${DB}.${TABLE}"
        BACKUP_FILE="${DB_DIR}/${TABLE}.sql"
        # 执行表备份(不包含存储过程、函数和事件)
        mysqldump \
            -h "${MYSQL_HOST}" \
            -P "${MYSQL_PORT}" \
            -u "${MYSQL_USER}" \
            -p${MYSQL_PASS} \
            --single-transaction \
            --triggers \
            --hex-blob \
            --opt \
            --set-gtid-purged=OFF \
            --default-character-set=utf8mb4 \
            --lock-tables=FALSE \
            --add-locks=FALSE \
            --skip-triggers \
            "${DB}" "${TABLE}" > "${BACKUP_FILE}" 2>> "${LOG_FILE}"
        if [ $? -eq 0 ]; then
            # 检查文件大小,如果太小可能是空表或备份失败
            FILE_SIZE=$(stat -c%s "${BACKUP_FILE}" 2>/dev/null || stat -f%z "${BACKUP_FILE}")
            if [ "${FILE_SIZE}" -lt 100 ]; then
                log "警告: 表 ${DB}.${TABLE} 的备份文件可能为空或异常"
            else
                log "成功备份表 ${DB}.${TABLE} 到 ${BACKUP_FILE} (大小: ${FILE_SIZE} 字节)"
            fi
        else
            log "错误: 备份表 ${DB}.${TABLE} 失败"
        fi
    done
done
# 备份完成统计
TOTAL_TABLES=0
for DB in ${DATABASES}; do
    if [ -d "${BACKUP_DIR}/${DB}" ]; then
        DB_TABLES=$(ls "${BACKUP_DIR}/${DB}"/*.sql 2>/dev/null | wc -l)
        TOTAL_TABLES=$((TOTAL_TABLES + DB_TABLES))
    fi
done
log "备份完成! 总共备份了 ${TOTAL_TABLES} 个表"
log "备份文件保存在: ${BACKUP_DIR}"

备份目录结构如下:

mysql-backup/
└── YYYYMMDD_HHMMSS/
    ├── backup.log
    ├── db1/
    │   ├── table1.sql
    │   ├── table2.sql
    │   └── ...
    ├── db2/
    │   ├── table1.sql
    │   ├── table2.sql
    │   └── ...
    └── ...

其中:

  • YYYYMMDD_HHMMSS 是备份时间戳(年、月、日、时、分、秒)
  • backup.log 是备份过程的日志文件
  • 每个数据库都有自己的目录,目录名与数据库名相同
  • 每个表都以 .sql 文件格式单独备份,文件名与表名相同

恢复脚本

这个恢复脚本是和上面备份脚本配套使用的,用于恢复指定数据库的备份。只能恢复一个数据库,但是也够用了。

restore-onedb.sh

#!/bin/bash
# MySQL 连接参数
MYSQL_HOST="127.0.0.1"
MYSQL_PORT="3306"
MYSQL_USER="root"
MYSQL_PASS="your_mysql_password"
# 检查参数
if [ $# -ne 2 ]; then
    echo "用法: $0 <备份目录路径> <数据库名>"
    echo "例如: $0 /opt/mysql-backup/20231201_143022 mydatabase"
    exit 1
fi
BACKUP_DIR="$1"
DB_NAME="$2"
DB_BACKUP_DIR="$BACKUP_DIR/$DB_NAME"
# 检查备份目录和数据库备份是否存在
if [ ! -d "$BACKUP_DIR" ]; then
    echo "错误: 备份目录不存在: $BACKUP_DIR"
    exit 1
fi
if [ ! -d "$DB_BACKUP_DIR" ]; then
    echo "错误: 在备份目录中未找到数据库 '$DB_NAME' 的备份"
    echo "可用的数据库备份:"
    find "$BACKUP_DIR" -maxdepth 1 -type d -not -path "$BACKUP_DIR" -not -name ".*" -exec basename {} \; | grep -v -E "(backup|log)"
    exit 1
fi
echo "开始恢复指定数据库"
echo "备份目录: $BACKUP_DIR"
echo "数据库名: $DB_NAME"
echo "MySQL 主机: $MYSQL_HOST:$MYSQL_PORT"
echo "=========================================="
# 确认操作
read -p "确认要恢复数据库 '$DB_NAME' 吗?这将删除现有数据库并重新导入!(y/N): " confirm
case "$confirm" in
    [yY]|[yY][eE][sS])
        echo "开始恢复..."
        ;;
    *)
        echo "操作已取消"
        exit 0
        ;;
esac
# 记录整个恢复过程的开始时间
OVERALL_START_TIME=$(date +%s)
# 检查数据库是否存在
DB_EXISTS=$(mysql -h "${MYSQL_HOST}" -P "${MYSQL_PORT}" -u "${MYSQL_USER}" -p${MYSQL_PASS} \
    -e "SHOW DATABASES LIKE '${DB_NAME}';" -s --skip-column-names 2>/dev/null)
if [ -n "$DB_EXISTS" ]; then
    echo "数据库 '$DB_NAME' 已存在,正在删除..."
    mysql -h "${MYSQL_HOST}" -P "${MYSQL_PORT}" -u "${MYSQL_USER}" -p${MYSQL_PASS} \
        -e "DROP DATABASE \`${DB_NAME}\`;" 2>/dev/null
    if [ $? -ne 0 ]; then
        echo "错误: 无法删除数据库 '$DB_NAME'"
        exit 1
    fi
    echo "数据库 '$DB_NAME' 已成功删除"
fi
# 创建新数据库
echo "创建数据库 '$DB_NAME'..."
mysql -h "${MYSQL_HOST}" -P "${MYSQL_PORT}" -u "${MYSQL_USER}" -p${MYSQL_PASS} \
    -e "CREATE DATABASE \`${DB_NAME}\` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;" 2>/dev/null
if [ $? -ne 0 ]; then
    echo "错误: 无法创建数据库 '$DB_NAME'"
    exit 1
fi
# 恢复所有表
TABLE_COUNT=0
FAILED_COUNT=0
echo "开始恢复表数据..."
echo "------------------------------------------"
for TABLE_FILE in "$DB_BACKUP_DIR"/*.sql; do
    if [ -f "$TABLE_FILE" ]; then
        TABLE_NAME=$(basename "$TABLE_FILE" .sql)
        # 记录单个表恢复的开始时间
        TABLE_START_TIME=$(date +%s)
        # 获取SQL文件大小
        FILE_SIZE=$(du -h "$TABLE_FILE" | cut -f1)
        echo "恢复表: $DB_NAME.$TABLE_NAME (文件大小: $FILE_SIZE)"
        # 恢复表
        mysql -h "${MYSQL_HOST}" -P "${MYSQL_PORT}" -u "${MYSQL_USER}" -p${MYSQL_PASS} \
            "$DB_NAME" < "$TABLE_FILE"
        if [ $? -eq 0 ]; then
            # 记录单个表恢复的结束时间
            TABLE_END_TIME=$(date +%s)
            TABLE_DURATION=$((TABLE_END_TIME - TABLE_START_TIME))
            # 查询表的行数
            ROW_COUNT=$(mysql -h "${MYSQL_HOST}" -P "${MYSQL_PORT}" -u "${MYSQL_USER}" -p${MYSQL_PASS} \
                -e "SELECT COUNT(*) FROM \`${DB_NAME}\`.\`${TABLE_NAME}\`;" -s --skip-column-names 2>/dev/null)
            if [ $? -eq 0 ]; then
                echo "✓ 成功恢复表: $DB_NAME.$TABLE_NAME | 耗时: ${TABLE_DURATION}秒 | 行数: $ROW_COUNT"
            else
                echo "✓ 成功恢复表: $DB_NAME.$TABLE_NAME | 耗时: ${TABLE_DURATION}秒 | 行数: 查询失败"
            fi
            TABLE_COUNT=$((TABLE_COUNT + 1))
        else
            echo "✗ 错误: 恢复表 $DB_NAME.$TABLE_NAME 失败"
            FAILED_COUNT=$((FAILED_COUNT + 1))
        fi
    fi
done
# 记录整个恢复过程的结束时间
OVERALL_END_TIME=$(date +%s)
OVERALL_DURATION=$((OVERALL_END_TIME - OVERALL_START_TIME))
echo "=========================================="
echo "数据库 '$DB_NAME' 恢复完成!"
echo "成功恢复表: $TABLE_COUNT 个"
if [ $FAILED_COUNT -gt 0 ]; then
    echo "恢复失败表: $FAILED_COUNT 个"
fi
echo "总耗时: ${OVERALL_DURATION} 秒"
echo "备份目录: $BACKUP_DIR"
# 显示数据库总行数统计
echo "------------------------------------------"
echo "数据库行数统计:"
TOTAL_ROWS=0
for TABLE_FILE in "$DB_BACKUP_DIR"/*.sql; do
    if [ -f "$TABLE_FILE" ]; then
        TABLE_NAME=$(basename "$TABLE_FILE" .sql)
        ROW_COUNT=$(mysql -h "${MYSQL_HOST}" -P "${MYSQL_PORT}" -u "${MYSQL_USER}" -p${MYSQL_PASS} \
            -e "SELECT COUNT(*) FROM \`${DB_NAME}\`.\`${TABLE_NAME}\`;" -s --skip-column-names 2>/dev/null)
        if [ $? -eq 0 ] && [ -n "$ROW_COUNT" ]; then
            echo "  $TABLE_NAME: $ROW_COUNT 行"
            TOTAL_ROWS=$((TOTAL_ROWS + ROW_COUNT))
        fi
    fi
done
echo "  总计: $TOTAL_ROWS 行"

restore-onedb.sh 脚本代码分析

该恢复脚本设计用于恢复单个数据库的备份,并提供了完善的错误处理、用户交互和统计功能。

  • 记录了整个恢复过程的开始和结束时间,以及每个表恢复的单独时间,便于性能分析和优化,特别是在处理大型数据库时。
  • 脚本会检查目标数据库是否存在,如果存在则先删除再创建,确保恢复环境干净。创建数据库时指定了字符集和排序规则为utf8mb4,支持完整的Unicode字符,确保数据编码正确性。
  • 脚本会查询每个恢复后的表的行数,用于验证数据恢复的完整性。

到此这篇关于一文分享MySQL数据库备份恢复脚本的文章就介绍到这了,更多相关MySQL数据库备份恢复内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • mysql 记录不存在时插入 记录存在则更新的实现方法

    mysql 记录不存在时插入 记录存在则更新的实现方法

    相信很多人都需要用到这个语句,请看下文:(在4.1以后的版本才有效)
    2008-08-08
  • MySQL从一个表中查出数据并插入到另一个表的详细处理方案

    MySQL从一个表中查出数据并插入到另一个表的详细处理方案

    这篇文章主要给大家介绍了关于MySQL从一个表中查出数据并插入到另一个表的详细处理方案,文中通过图文介绍的非常详细,对大家学习或者使用MySQL具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-12-12
  • Linux连接mysql报错:Access denied for user ‘root’@‘localhost’(using password: YES)的解决方法

    Linux连接mysql报错:Access denied for user ‘root’@‘localhost’(usi

    这篇文章主要给大家介绍了关于Linux连接mysql数据库报错:Access denied for user ’root‘@’localhost‘(using password: YES)的解决方法,文中通过示例代码介绍的非常详细,需要的朋友可以参考借鉴,下面随着小编来一起学习学习吧。
    2018-01-01
  • MySQL故障切换笔记之应用无感知设计详解

    MySQL故障切换笔记之应用无感知设计详解

    这篇文章主要给大家介绍了关于MySQL故障切换笔记之应用无感知设计的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用mysql具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2018-08-08
  • MySQL的两种分页方式之Offset/Limit分页和游标分页详解

    MySQL的两种分页方式之Offset/Limit分页和游标分页详解

    这篇文章主要对比了MySQL的Offset/Limit分页与游标分页,指出前者简单但存在数据漂移和性能缺陷,后者通过游标避免这些问题且更高效,建议根据业务场景选择分页方式,深度分页或动态数据宜用游标分页,而延迟联结可优化Offset/Limit性能,需要的朋友可以参考下
    2025-09-09
  • mysql千万级数据大表该如何优化?

    mysql千万级数据大表该如何优化?

    如何设计或优化千万级别的大表?此外无其他信息,个人觉得这个话题有点范,就只好简单说下该如何做,对于一个存储设计,必须考虑业务特点,收集的信息如下
    2011-08-08
  • MySQL快速插入大量数据的解决方案和代码示例

    MySQL快速插入大量数据的解决方案和代码示例

    在这篇博客中,我们将深入探讨如何高效插入大量数据到MySQL数据库,无论你是数据库新手还是经验丰富的开发者,这篇文章都将为你提供实用的解决方案和代码示例,帮助你解决插入3万条数据需要20多秒的问题,需要的朋友可以参考下
    2024-08-08
  • SQL字符串以及数字常用操作汇总

    SQL字符串以及数字常用操作汇总

    本篇文章是对SQL字符串以及数字的常用操作进行了详细的总结与分析,需要的朋友参考下
    2013-06-06
  • MySQL insert 记录后查询乱码问题解决方法

    MySQL insert 记录后查询乱码问题解决方法

    文章通过分析一个MySQL插入数据后查询乱码的问题,探讨了乱码的原因,并提出了解决方法,问题的根本原因是MySQL客户端和服务器之间的字符集不一致,导致插入的中文字符被错误解码为乱码,感兴趣的朋友跟随小编一起看看吧
    2024-11-11
  • 免安转MySQL服务的启动与停止方法

    免安转MySQL服务的启动与停止方法

    免安转MySQL服务的启动与停止方法,可以不用安装解压以后即可执行,对于老手推荐,新手建议用安装版本。
    2011-03-03

最新评论