mysqldump 备份必须加 --single-transaction 保证 innodb 一致性,搭配 --routines、--triggers,显式指定库名;用 systemd timer 替代 crontab,依赖 mysql 服务;备份压缩校验、分层保留;密码存 ~/.my.cnf 并设 chmod 600;定期验证恢复。

备份脚本里 mysqldump 的关键参数必须加 --single-transaction
不加这个参数,备份时遇到写入操作容易产生不一致快照,尤其在业务高峰期。InnoDB 表虽支持事务,但 mysqldump 默认不启用事务一致性导出——它会逐表 dump,中间若有 DML 操作,备份出来的 SQL 可能跨事务状态。
实操建议:
-
--single-transaction仅对 InnoDB 有效,MyISAM 表仍需配合--lock-all-tables(但会锁库,慎用) - 务必搭配
--routines和--triggers,否则存储过程和触发器不会被导出 - 避免用
--all-databases直接备份全部库,权限不足或含系统库(如information_schema)会报错;推荐显式指定库名:mysqldump -u root -p'pwd' --single-transaction --routines --triggers myapp_db > /backup/myapp_db_$(date +\%Y\%m\%d).sql
定时任务用 crontab 还是 systemd timer?选后者更可靠
crontab 在系统重启后自动生效,但无法感知 MySQL 服务是否就绪;systemd timer 可设依赖关系,且支持日志追踪、失败重试。
实操建议:
- 写一个 service 文件
/etc/systemd/system/mysql-backup.service,ExecStart指向你的备份脚本路径 - 配套 timer 文件
mysql-backup.timer,用OnCalendar=daily并加上Requires=mysql.service和After=mysql.service - 运行
systemctl daemon-reload && systemctl enable mysql-backup.timer && systemctl start mysql-backup.timer - 检查状态:用
systemctl list-timers看下次触发时间,journalctl -u mysql-backup.service查错误
备份文件保留策略别只靠 find -mtime +7 -delete
直接删旧文件风险高:磁盘满、误删、没校验备份有效性就删了,恢复时才发现 SQL 文件损坏或为空。
实操建议:
- 先用
gzip压缩备份文件,节省空间同时自带校验(解压失败即知损坏) - 保留前 7 天 + 每月 1 号的完整备份,用日期判断:
if [[ $(date +\%d) == "01" ]]; then keep_flag="monthly"; else keep_flag="daily"; fi - 清理前先
head -n 20 /backup/*.sql.gz | grep -q "MySQL dump" || echo "警告:疑似空或损坏" - 删除动作加
-v参数并记录到日志,例如:find /backup -name "*.sql.gz" -mtime +7 -print -delete >> /var/log/mysql-backup-clean.log 2>&1
密码不能硬编码在脚本里,用 ~/.my.cnf 配置文件更安全
脚本里写 -p'your_password' 或 export MYSQL_PWD=xxx 都会在进程列表(ps aux)中暴露密码,且 git 提交易泄露。
实操建议:
- 创建
~/.my.cnf,内容为:
[client] user = backup_user password = your_strong_password host = localhost
chmod 600 ~/.my.cnf,否则 mysqldump 会拒绝读取GRANT SELECT, LOCK TABLES, SHOW VIEW, TRIGGER ON myapp_db.* TO 'backup_user'@'localhost';
mysqldump myapp_db > ...,无需再传用户密码参数真正麻烦的不是写脚本,是验证备份可恢复——每周至少手动 mysql -D test_restore 试一次,否则你永远不知道那个 gzip 文件到底有没有用。











