生产环境全库备份需用mysqldump加–single-transaction、–routines、–triggers、–events、–default-character-set=utf8mb4、–hex-blob、–set-gtid-purged=OFF,并强制TCP连接、按时间戳命名+gzip压缩,且脚本中所有命令须写绝对路径。

用 mysqldump 做全库备份,关键在参数组合
直接执行 mysqldump -u root -p database_name 很容易失败,不是权限问题就是锁表中断。生产环境必须加 --single-transaction(InnoDB 专用)和 --routines --triggers --events,否则存储过程、触发器会丢失。--skip-lock-tables 要慎用——它不适用于 MyISAM 表,且可能造成备份不一致。
实际脚本中建议固定使用:
-
--default-character-set=utf8mb4:避免中文乱码 -
--hex-blob:安全导出 BLOB 类型(如图片、加密字段) -
--set-gtid-purged=OFF:关闭 GTID 记录,否则恢复时可能报错ERROR 1840 (HY000) - 加上
-h 127.0.0.1强制走 TCP 连接,绕过 Unix socket 权限限制
按日期自动命名 + 压缩归档,防止磁盘写满
不带时间戳的备份文件会互相覆盖,而裸 SQL 文件体积大、传输慢。脚本里必须用 $(date +/%Y/%m/%d_/%H/%M) 生成唯一文件名,并立刻用 gzip 压缩。别用 bzip2 或 xz——它们压缩快但 CPU 占用高,夜间备份可能拖慢数据库响应。
示例片段(Shell):
DB_NAME="myapp"
DUMP_FILE="/backup/${DB_NAME}_$(date +/%Y/%m/%d_/%H/%M).sql.gz"
mysqldump -h 127.0.0.1 -u backup_user -p'xxx' --single-transaction --routines --triggers --events --set-gtid-purged=OFF --default-character-set=utf8mb4 "$DB_NAME" | gzip > "$DUMP_FILE"
注意:backup_user 需提前授权:GRANT SELECT, LOCK TABLES, SHOW VIEW, TRIGGER ON /`myapp/`.* TO 'backup_user'@'localhost';
用 mysql 命令恢复时,忽略错误比中断更实用
直接 mysql -u root -p database_name 遇到已存在表、重复主键就会停住。线上恢复不能人工干预,得加 --force 参数让命令跳过错误继续执行。但要注意:--force 不会跳过语法错误,所以备份前务必验证 SQL 可执行性(可用 mysql -e "source /path/to/backup.sql;" 测试)。
恢复脚本关键点:
- 先创建空库:
mysql -e "CREATE DATABASE IF NOT EXISTS $DB_NAME CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;" - 再导入:
zcat "$DUMP_FILE" | mysql -u root -p'xxx' --force "$DB_NAME" - 最后检查行数是否明显异常(比如比上次少 90%),可加一句
mysql -Nse "SELECT COUNT(*) FROM $DB_NAME.table1"做简单校验
crontab 定时任务要避开高峰,且必须重定向日志
每天凌晨 2 点跑备份看似合理,但如果数据库凌晨有批量导入或报表任务,IO 就会打满。建议设为 0 3 * * * (3 点)并配合 ionice -c2 -n7 降低 IO 优先级。
crontab 行必须带完整路径和日志重定向,否则失败了根本看不到报错:
0 3 * * * /usr/bin/ionice -c2 -n7 /bin/bash /opt/scripts/mysql_backup.sh >> /var/log/mysql_backup.log 2>&1
最容易被忽略的是:脚本里所有命令(mysqldump、mysql、date)都要写绝对路径,cron 默认 PATH 很窄,which mysqldump 结果才是真实路径。
