Skip to main content

Command Palette

Search for a command to run...

MySQL数据库备份及导入脚本

Published
2 min read
MySQL数据库备份及导入脚本
H

I am ZhangSan, a mere nobody. 我是张三,一个无名小子。

总是忘记数据库的数据备份,所以写了一个脚本来备份。

最近发现表已经增加的比较大了,单进程的导入脚本时间比较长,所以更新了脚本支持并发导入。

并发数量设置时,请注意目标服务器的负载情况。

表特别多可以并发进行单表备份,以下为数据库导出、导入支持指定表的全功能脚本示例(注意替换变量后使用):

#--------------------------------- config -------------------------------------
# 数据库信息设置(内网地址只读实例) 生产库
DB_HOST="demo"
DB_USER="demo"
DB_PASS="demo"
DB_NAME="demo"

# 目标库切换vpc内网
TARGET_DB_HOST="jeeinn"
TARGET_DB_USER="jeeinn"
TARGET_DB_PASS="jeeinn"
TARGET_DB_NAME="jeeinn"

# 定义备份文件目录
BACKUP_DIR="/data/backup/tmp"
# 最大并发数
MAX_EXPORT_JOBS=4
MAX_IMPORT_JOBS=6

# 导出指定表
TABLES=(
  tb1
  tb2_jeeinn
)

#--------------------------------- start -------------------------------------

# 开始执行
mkdir -p "${BACKUP_DIR}"
echo "[$(date "+%Y-%m-%d %H:%M:%S")] Start sync data..."
# 备份函数
backup_table() {
  local table=$1
  local backup_file="${BACKUP_DIR}/${table}.sql"
  local run_log="${BACKUP_DIR}/${table}_run.log"

  echo "[$(date "+%Y-%m-%d %H:%M:%S")] Exporting table $table..." >> "${run_log}"
  if /usr/bin/mysqldump -h${DB_HOST} -u${DB_USER} -p${DB_PASS} \
    --set-gtid-purged=off \
    --default-character-set=utf8 \
    --single-transaction ${DB_NAME} "${table}" > "$backup_file"; then
    echo "[$(date "+%Y-%m-%d %H:%M:%S")] Export succeeded: ${backup_file}" >> "${run_log}"
  else
    echo "[$(date "+%Y-%m-%d %H:%M:%S")] Export failed: ${table}" >> "${run_log}"
  fi
}

# 并发备份控制
current_jobs=0
for table in "${TABLES[@]}"; do
    backup_table "$table" &
    ((current_jobs++))
    if (( current_jobs >= MAX_EXPORT_JOBS )); then
        wait -n  # 等待任意一个后台任务完成
        ((current_jobs--))
    fi
done
wait  # 等待所有剩余后台任务完成
echo "[$(date "+%Y-%m-%d %H:%M:%S")] Export completed"


# 导入函数
import_table() {
  local table=$1
  local backup_file="${BACKUP_DIR}/${table}.sql"
  local run_log="${BACKUP_DIR}/${table}_run.log"

  echo "[$(date "+%Y-%m-%d %H:%M:%S")] Importing table $table..." >> "${run_log}"
  if /usr/bin/mysql -h${TARGET_DB_HOST} -u${TARGET_DB_USER} -p${TARGET_DB_PASS} \
    --default-character-set=utf8 \
    --init-command="SET autocommit=0; SET foreign_key_checks=0;" ${TARGET_DB_NAME} < "$backup_file"; then
    echo "[$(date "+%Y-%m-%d %H:%M:%S")] Import succeeded: ${backup_file}" >> "${run_log}"
  else
    echo "[$(date "+%Y-%m-%d %H:%M:%S")] Import failed: ${table}" >> "${run_log}"
  fi
}

# 并发导入控制
current_jobs=0
for table in "${TABLES[@]}"; do
    import_table "$table" &
    ((current_jobs++))
    if (( current_jobs >= MAX_IMPORT_JOBS )); then
        wait -n
        ((current_jobs--))
    fi
done
wait
echo "[$(date "+%Y-%m-%d %H:%M:%S")] Import completed"

# 合并日志
echo "[$(date "+%Y-%m-%d %H:%M:%S")] Merging run log..."
cat ${BACKUP_DIR}/*_run.log > "${BACKUP_DIR}/db_sync_run_$(date "+%Y%m%d").log"
rm -f ${BACKUP_DIR}/*_run.log
echo "[$(date "+%Y-%m-%d %H:%M:%S")] Merge run log competed"

更新于2025-09-22 20:39:24


按提示设置相应的数据库选项和备份文件存放地即可,支持排除表

#!/bin/bash
#获取当前时间
TODAY=$(date "+%Y%m%d_%H%M")
#定义备份文件目录
BACK_FOLDER="/mnt/db_back"
#数据库信息设置
HOST="localhost"
USRENAME="root"
PASSWORD="root"
DATABASE="test"

#定义备份文件名
FILE_NAME="${DATABASE}_${TODAY}.sql"
BACK_FILENAME="${BACK_FOLDER}/${FILE_NAME}"

#排除的数据表
EXCLUDED_TABLES=(
db_log
)
IGNORED_TABLES_STRING=''
for TABLE in "${EXCLUDED_TABLES[@]}"
do :
   IGNORED_TABLES_STRING+=" --ignore-table=${DATABASE}.${TABLE}"
done

#执行备份
/usr/bin/mysqldump -h${HOST} -u${USRENAME} -p${PASSWORD} \
--single-transaction \         # 对InnoDB做非阻塞备份
--quick \                      # 避免内存溢出
--skip-add-drop-table \        # [可选]防止drop现有表
--set-gtid-purged=OFF \        # 如果不需要GTID
--hex-blob \                   # 如果有二进制数据
--default-character-set=utf8 \ #设置字符集
--set-gtid-purged=off \        #关闭gtid
${IGNORED_TABLES_STRING} ${DATABASE} > ${BACK_FILENAME}

#压缩备份文件并删除源文件
cd ${BACK_FOLDER}
tar -zcf ${FILE_NAME}.tar.gz ${FILE_NAME} --remove-files

# 删除超时的跟压缩的文件
BEFORE=$(date -d"15 day ago" +%Y%m%d_%H%M)
rm -f "${DATABASE}_${BEFORE}.sql.tar.gz";

echo "finish BACK mysql database ${DATABASE}."

你也可以选择合适的备份方式,来随意修改。

使用客户端导入

/usr/bin/mysql -h${TARGET_HOST} -u${TARGET_USERNAME} -p${TARGET_PASSWORD} \
--default-character-set=utf8 \ #设置字符集
--init-command="SET SESSION autocommit=0; SET SESSION unique_checks=0;
SET SESSION foreign_key_checks=0; SET SESSION sql_log_bin=0;" \ # 设置会话参数
${TARGET_DATABASE} < ${TMP_BACK_FILENAME}

注:使用 --init-command 参数某些导入会报权限错误,将该参数中SET SESSION sql_log_bin=0;移除即可

示例错误ERROR 1227 (42000): Access denied; you need (at least one of) the SUPER privilege(s) for this operation

More from this blog

git切换分支缓慢问题

背景 最近在项目中 test 分支与 master 分支切换时感到非常慢,大概需要1-2分钟 解决 找出两个分支的最大的差异 # 找出两个分支的差异 git diff --dirstat=files master..test # 输出 98.7% vendor/alipaysdk/openapi/v2/aop/request/ 分别检出两个分支到不同目录,经过比较发现文件主要差异为行尾表现不同,master 分支的文件为 LF、test 分支的为 CRLF。 处理方案 使用 .gitatt...

Feb 10, 20261 min read7

软件生产范式: 从 Ddd 到 Sdd + Tdd 的未来之路

未来的软件系统,很可能不再依赖大量手写的代码,而是依赖可验证的业务规范,以及对这些规范的自动化实现。——这正是从 DDD → SDD + TDD 的演进方向。 在 AI 深度参与软件开发的时代,传统的代码中心开发方式正在加速老化。我们正在经历一次结构性转变:从“写代码”转向“写规范 + 写测试 + 让 AI 自动补全逻辑”。 这篇文章试图提供一个前瞻性的观点(深度使用 vibe coding 近

Dec 9, 20253 min read21
软件生产范式: 从 Ddd 到 Sdd + Tdd 的未来之路

多项目部署时使用不同node版本与包管理器

nvm 项目地址:https://github.com/nvm-sh/nvmcorepack 项目地址:https://github.com/nodejs/corepack#readme 场景 前端多项目依赖不同的 nodejs 版本和不同的包管理器(npm、yarn、pnpm) 解决方案 1、依赖不同 nodejs 版本使用 nvm 来解决,项目中新增 .nvmrc 来指定版本号 2、针对不同包管理器的问题使用node自带的 corepack 来解决 # 使用指定版本 node nvm us...

Nov 5, 20251 min read1

hello1024

46 posts