推荐使用 mysqldump 工具导出 MySQL 数据库,配合 --single-transaction --routines --triggers --events 等参数保证一致性与完整性,并通过 subprocess.run() 安全调用,避免 shell 注入和静默失败。

用 mysqldump 命令导出数据库,别写 Python 封装逻辑
Python 本身不直接读取 MySQL 数据文件,也不推荐用 mysql-connector-python 或 pymysql 一行行查表导出 —— 这样既慢又容易丢结构(比如视图、存储过程、字符集设置)。真正可靠、标准的方式是调用系统自带的 mysqldump 工具。
实操建议:
- 确保服务器已安装 MySQL 客户端工具:
mysqldump --version能正常返回 - 用
--single-transaction --routines --triggers --events参数保证一致性与完整性 - 避免在命令里硬编码密码:用
~/.my.cnf配置文件存认证信息,权限设为600 - 导出时加
--set-gtid-purged=OFF(如果没开 GTID)或--set-gtid-purged=AUTO(开了 GTID),否则可能报错
用 subprocess.run() 调用 mysqldump,别用 os.system()
os.system() 无法捕获错误码和输出,出问题时脚本静默失败;而 subprocess.run() 可控性高、易调试。
关键点:
立即学习“Python免费学习笔记(深入)”;
- 用
shell=False+ 列表传参,防 shell 注入(尤其库名含破折号或空格时) - 显式指定
encoding='utf-8'和errors='replace',避免中文库名或注释导致解码异常 - 检查
result.returncode != 0,并打印result.stderr—— 很多备份失败其实就卡在权限或连接超时 - 导出路径建议用绝对路径,比如
/backup/mysql/20240520_myapp.sql,别依赖当前工作目录
用 gzip 命令压缩,别用 zlib 在 Python 里读写
用 Python 的 gzip 模块读取大 SQL 文件再压缩,会把整个文件加载进内存,1GB 的库可能吃光 2GB 内存。更稳的做法是让 mysqldump 直接管道给 gzip。
示例命令组合(安全且高效):
mysqldump -u backup_user -h 127.0.0.1 myapp | gzip > /backup/mysql/myapp_$(date +\%Y\%m\%d).sql.gz
如果必须用 Python 控制流程,就用 subprocess.Popen 连接两个进程:
- 第一个进程:
['mysqldump', '-u', 'backup_user', 'myapp'] - 第二个进程:
['gzip', '-c'],用stdin=subprocess.PIPE接前者的 stdout - 最后重定向到文件句柄,避免中间临时文件
加时间戳和保留策略,不然硬盘迟早被占满
每天一个备份文件不清理,三个月就是 90 个文件;MySQL 的 mysqldump 默认不带时间戳,得自己拼。
注意细节:
- 用
datetime.now().strftime('%Y%m%d_%H%M')生成文件名,比time.time()更可读 - 删除旧备份别只看文件名日期:用
os.path.getmtime()按真实修改时间删,防止因系统时间跳变导致误删 - 保留最近 7 天 + 每月 1 号各一份:先按日期分组,再分别判断,比简单
ls | head -n -7 | xargs rm更可靠 - 压缩包生成后,用
gzip -t校验完整性(尤其 NFS 或低配 VPS 上容易写损坏)
最常被忽略的是权限和 SELinux —— 即使脚本跑通了,mysqldump 也可能因 SELinux 策略被拦截,日志里只显示 “permission denied”,得查 ausearch -m avc -ts recent。


















