Linux项目

【1.0手动构建】编写Shell脚本实现mysqldump定时全量备份

2026-05-05 16:46 · 0 次阅读 · 3 分钟阅读 · 添加评论
📑 文章目录 收起 ▴

部署前提和账户

部署目标:

  • 源: WordPress博客的数据库wordpress,运行在MySQL 8.0里
  • 目标: 每天凌晨3点自动备份到一个目录/data/backup/mysql
  • 清理策略: 只保留最近7天的备份,过期自动删除
  • 运维边界: 不用root跑,用你博客自己的数据库用户(后面会提到权限限制)
# 登录MySQL,查看当前用户权限
mysql -u root -p
SHOW GRANTS FOR '你的博客用户'@'localhost';

先跑通一条mysqldump命令

在服务器上终端先手工执行一次,确保能备份出来:

  • -u:数据库用户名
  • -p:密码(后面写脚本会分离到配置文件)
  • 数据库名放在最后,重定向>输出到文件
mysqldump -u你的博客用户 -p你的密码 wordpress > /tmp/test_backup.sql

创建备份脚本(重点)

创建脚本 /opt/scripts/mysql_backup.sh 写入:
#!/bin/bash

# ===== 配置区 =====
BACKUP_DIR="/data/backup/mysql"          # 备份存放目录
DB_NAME="wordpress"                      # 要备份的数据库
DB_USER="你的博客用户"                    # 数据库账号
DB_PASS="你的密码"                       # 数据库密码
RETENTION_DAYS=7                         # 保留天数


# ===== 自动变量 =====
DATE=$(date +%Y%m%d_%H%M%S)              # 当前时间戳
BACKUP_FILE="$BACKUP_DIR/${DB_NAME}_${DATE}.sql"

# ===== 确保备份目录存在 =====
mkdir -p $BACKUP_DIR

# ===== 执行备份 =====
mysqldump \
  --single-transaction \
  --routines \
  --triggers \
  -u$DB_USER \
  -p$DB_PASS \
  $DB_NAME > $BACKUP_FILE

# ===== 检查是否备份成功 =====
if [ $? -eq 0 ]; then
    echo "[$(date)] 备份成功:$BACKUP_FILE" >> $BACKUP_DIR/backup.log
else
    echo "[$(date)] 备份失败!" >> $BACKUP_DIR/backup.log
    exit 1
fi

# ===== 清理7天前的旧备份 =====
find $BACKUP_DIR -name "*.sql" -mtime +$RETENTION_DAYS -delete
echo "[$(date)] 已清理${RETENTION_DAYS}天前的旧备份" >> $BACKUP_DIR/backup.log

代码详解

第 1 行:

/bin/bash 是 Bash 解释器的绝对路径

第 3-8 行:配置区:

BACKUP_DIR=”/data/backup/mysql”
DB_NAME=”wordpress”
DB_USER=”你的博客用户”
DB_PASS=”你的密码”
RETENTION_DAYS=7

  • 变量命名习惯: 全大写表示常量/配置项,一目了然
  • 为什么不用写死在命令里: 如果备份目录变了、数据库改名了,只改这里就行,不用去命令堆里找
  • RETENTION_DAYS=7 保留 7 天的备份,7 天前的自动删除。如果以后想改成 30 天,只改这一个数字

第 11-12 行:自动变量

DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE=”$BACKUP_DIR/${DB_NAME}_${DATE}.sql”

11行: 生成一个时间戳字符串,避免每次备份文件名重复。

  • $(命令) 是命令替换语法,把命令的输出结果赋值给变量
  • date +%Y%m%d_%H%M%S 会输出类似 20260513_030000 的时间戳
    • %Y 四位年份,%m 两位月份,%d 两位日期
    • %H 24小时制小时,%M 分钟,%S 秒

12行: 拼接出完整的备份文件路径。

  • ${变量名} 是变量引用的完整写法,防止变量和后面字符粘连
  • 拼接结果示例:/data/backup/mysql/wordpress_20260513_030000.sql

第 15 行:

mkdir -p $BACKUP_DIR

作用: 确保备份目录存在。

详细解释:

  • mkdir 创建目录
  • -p 参数:如果目录已存在不报错,如果父目录也不存在会一并创建(比如 /data/backup/mysql 三级一次性建好)
  • 没有 -p 的话,目录不存在会报错中断脚本

第 18-23 行:执行备份:

mysqldump \
–single-transaction \
–routines \
–triggers \
-u$DB_USER \
-p$DB_PASS \
$DB_NAME > $BACKUP_FILE

第 18 行作用: 调用 mysqldump 命令,\ 表示换行继续(为了可读性,把长命令折成多行)。

第 19 行 --single-transaction

  • 对 InnoDB 表开启一个事务,在整个备份过程中读取事务开始时的快照数据
  • 好处:备份期间不锁表,网站正常读写不受影响
  • 这是生产环境备份的标配参数

第 20 行 --routines

  • 连存储过程(Stored Procedure)和函数一起备份
  • WordPress 一般没有存储过程,但加上没坏处

第 21 行 --triggers

  • 连触发器(Trigger)一起备份
  • 同样,WordPress 一般没有,但加了有备无患

第 22-23 行 -u$DB_USER -p$DB_PASS

  • -u 指定数据库用户名,-p 指定密码
  • 注意 -p$DB_PASS 之间没有空格——MySQL 命令行工具的规则,有空格的 -p 密码 会被误解为“交互式输入密码 + 密码是另一个参数”

第 24 行 $DB_NAME > $BACKUP_FILE

  • 指定要备份的数据库名
  • > 是输出重定向,把 mysqldump 输出的 SQL 内容写入到 $BACKUP_FILE 文件里

第 27-32 行:检查备份是否成功

if [ $? -eq 0 ]; then
echo “[$(date)] 备份成功:$BACKUP_FILE” >> $BACKUP_DIR/backup.log
else
echo “[$(date)] 备份失败!” >> $BACKUP_DIR/backup.log
exit 1
fi

第 27 行 if [ $? -eq 0 ]; then

详细拆解:

  • $? 是 Shell 的特殊变量,保存了上一条命令的退出状态码
  • 0 表示上一条命令(mysqldump)执行成功
  • 非 0 表示出了某种错误(连接失败、权限不够、磁盘满等)
  • [ ... ] 是 test 命令的简写,做条件判断
  • -eq 是 equal 的意思,数字相等判断
  • if; then 开启条件分支

第 28 行:备份成功时做的事

  • echo "[$(date)] 备份成功:$BACKUP_FILE"
  • 输出类似:[Mon May 13 03:00:00 CST 2026] 备份成功:/data/backup/mysql/wordpress_20260513_030000.sql
  • >> 是追加重定向,把内容追加到日志文件末尾,不会覆盖之前的日志
  • $(date) 不加格式参数时输出完整日期时间字符串,带星期和时区

第 30 行:备份失败时做的事

  • 同样往日志写一行,标记失败

第 31 行 exit 1

  • 以退出码 1 终止脚本
  • 1 表示异常退出,这样如果外面有其他脚本调用这个备份脚本,就能通过 $? 知道它失败了

第 32 行 fi

  • if 语句的结束标记(if 倒过来写)

第 35-36 行:清理旧备份

find $BACKUP_DIR -name “*.sql” -mtime +$RETENTION_DAYS -delete
echo “[$(date)] 已清理${RETENTION_DAYS}天前的旧备份” >> $BACKUP_DIR/backup.log

第 35 行作用: 删除 7 天前的旧备份文件,防止磁盘被撑满。

详细拆解 find 命令:

  • find $BACKUP_DIR:在备份目录下查找
  • -name "*.sql":只匹配以 .sql 结尾的文件(避免误删日志或其他文件)
  • -mtime +7:文件最后修改时间距今超过 7 天
    • +7 是“大于 7 天”
    • 7 是“恰好 7 天前的那一天”
    • -7 是“小于 7 天”(最近 7 天内)
  • -delete:直接删除匹配的文件

第 36 行: 往日志追加一行清理记录,方便追踪。

设计考虑

第一个是配置集中管理,变量都放在开头,维护方便。

第二个是加入了成功/失败的判断和日志记录,不是盲跑,出了问题能追溯。

第三个是用 find -mtime 实现备份滚动清理,防止磁盘被占满。

第四个是 --single-transaction 参数保证备份期间业务不中断。

后续把密码迁移到 .my.cnf 凭证文件里,提高安全性。

密码安全处理(提高安全性可不加)

把密码明文写在脚本里是个安全漏洞。用MySQL的--defaults-extra-file机制隔离出来。

创建一个只有你的用户能读的配置文件:
# 写入配置文件
cat > /opt/scripts/.my.cnf <<EOF
[client]
user=你的博客用户
password=你的密码
EOF

#这里的 [client] 是选项组,它下面定义的 user 和 password 会被所有标准的 MySQL 客户端程序读取,例如 mysql 和 mysqldump。

# 最关键一步:将权限设为600,只有文件所有者可读写
chmod 600 /opt/scripts/.my.cnf

#如果权限设置太宽松(比如 644),mysqldump 等程序可能会因为认为文件不安全而拒绝读取它。
把脚本里的-u-p参数全部换成:
mysqldump \
  --defaults-extra-file=/opt/scripts/.my.cnf \
  --single-transaction \
  --routines \
  --triggers \
  $DB_NAME > $BACKUP_FILE

原代码:

mysqldump \
–single-transaction \
–routines \
–triggers \
-u$DB_USER \
-p$DB_PASS \
$DB_NAME > $BACKUP_FILE

ps:--defaults-extra-file 是一个命令行选项,用来告诉 MySQL 客户端程序(如 mysqlmysqldump)在一个额外的、用户指定的文件里读取配置参数。

定时执行(crontab)

执行顺序:
crontab -e
局部截取 20260513 092538 1024x346

ps:第一次使用crontab会提示用哪个工具,注意区分,选1就行

进入编辑器后,用方向键把光标移到文件内容的最后一行空行,粘贴或手动输入:

0 3 * * * /bin/bash /opt/scripts/mysql_backup.sh

注意五个星号之间都要有空格,这个格式很严格:

  • 分 时 日 月 周 命令
  • 0 3 * * * 表示每天凌晨 3 点 0 分

保存并退出 nano

  • Ctrl + O(字母o)→ 回车确认保存
  • 选择保存位置:File Name to Write: /tmp/crontab.C9ND7V/crontab
  • Ctrl + X 退出

最后确认定时任务生效:

crontab -l

屏幕上应该输出:

0 3 * * * /bin/bash /opt/scripts/mysql_backup.sh

只要看到这一行,就说明定时任务已经写入 root 的 crontab

确认生效

crontab -l          # 查看当前定时任务
tail -f /data/backup/mysql/backup.log   # 查看日志输出

恭喜你完成了所有步骤!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注