Go 中 exec mysqldump 常失败因默认走 socket(权限受限)且密码明文传参不安全;应改用 -h 127.0.0.1 强制 TCP、--defaults-extra-file 传密、检查磁盘空间与输出长度,并用 CombinedOutput 捕获错误。

Go 里直接 exec mysqldump 为什么常失败?
不是 Go 不行,是 mysqldump 对环境太敏感:它默认走 socket 连接,而 Go 进程往往没权限访问 /var/run/mysqld/mysqld.sock;另外,密码明文传参会被 shell 历史记录或 ps 看见,还容易被空格、特殊字符搞崩。
- 用
-h 127.0.0.1强制走 TCP,避开 socket 权限问题 - 别把密码塞进命令参数,改用
--defaults-extra-file指向临时配置文件 - 确保执行用户对目标目录有写权限,且磁盘空间足够——
mysqldump生成的是未压缩的 SQL 文本,1GB 库可能产出 3GB+ 文件
怎么安全传参并捕获 mysqldump 错误?
exec.Command 启动后必须显式调用 cmd.CombinedOutput() 或分别读 Stdout/Stderr,否则错误会静默丢失。常见现象是备份文件为空,但 Go 程序却返回 nil error。
- 用
os.CreateTemp生成带随机后缀的my.cnf临时文件,写入[client]段和user/password/host字段 - 命令参数按顺序拼:
mysqldump,--defaults-extra-file=/tmp/my.cnf.XYZ,--single-transaction,--routines,dbname - 检查
err是否非 nil,再检查len(output)是否为 0——两者都得看,缺一不可
恢复时用 mysql 命令要注意哪些坑?
恢复比备份更脆弱:SQL 文件里可能含 CREATE DATABASE、USE、字符集声明,如果目标库已存在或 collation 不匹配,mysql 会中途退出,但 Go 的 cmd.Run() 可能不报错。
- 先用
mysql -Nse "SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME='dbname'"检查库是否存在 - 恢复前加
--init-command="SET NAMES utf8mb4;",避免因连接默认字符集导致乱码或中断 - 不要依赖
mysql db_name 这种重定向——重定向在 Go 里要手动设 <code>cmd.Stdin,出错难调试;改用cmd.Stdin = bytes.NewReader(dumpBytes)更可控
要不要在 Go 里做压缩或分片?
直接让 mysqldump 输出到 gzip 管道看似省事,但在 Go 里链式 exec 容易卡死(比如 gzip 缓冲区满,mysqldump 写不进去),而且无法感知中间任一环节失败。
立即学习“go语言免费学习笔记(深入)”;
- 先 dump 到临时文件,再用
gzip单独压缩——两步分离,各自 handle error - 超大库(>5GB)别一次 dump 全库,用
--ignore-table=db.table1排除日志表,或按表拆成多个exec.Command并发跑(注意 MySQL 连接数限制) - 恢复时若文件是 .sql.gz,必须先
gunzip -c解压到 pipe,再喂给mysql;别试图用 Go 解压后全 load 到内存——10GB SQL 解压后可能吃光内存
真正麻烦的从来不是调哪个函数,而是 mysqldump 和 mysql 这两个外部命令在不同 MySQL 版本、不同 OS 用户权限、不同字符集配置下的行为漂移——每次换环境都得重新验证参数组合。











