mysqldump 备份时加 --single-transaction
有什么用
对 InnoDB 表做一致性备份时,
--single-transaction是关键参数。它通过在导出开始时启动一个 REPEATABLE READ 事务,确保整个 dump 过程看到的是同一时间点的数据快照,避免锁表又不丢一致性。
常见错误是没加这个参数却以为“没锁表就安全”——其实
mysqldump默认会执行
FLUSH TABLES WITH READ LOCK(需 SUPER 权限),导致写入阻塞。而加了
--single-transaction后,只要表全是 InnoDB,就完全不锁表。 仅对 InnoDB 有效;MyISAM 表仍会触发全局只读锁 必须搭配
--all-databases或指定库名使用,不能单独用在单表上还指望事务生效 如果备份期间有长事务运行,可能导致 dump 等待或失败,注意监控
INFORMATION_SCHEMA.INNODB_TRX
恢复时遇到 ERROR 1046 (3D000): No database selected
这是最常见的恢复失败提示,本质是 SQL 文件里没有
USE `db_name`;语句,或者你用
mysql命令时没指定目标库。
正确做法分两种场景:
备份的是单个库(如mysqldump myapp > backup.sql):恢复时必须显式指定库名:
mysql myapp < backup.sql备份含
--databases(如
mysqldump --databases myapp > backup.sql):SQL 文件开头有
CREATE DATABASE IF NOT EXISTS `myapp`;和
USE `myapp`;,此时可直接执行:
mysql < backup.sql,但要求目标实例上该库尚不存在,否则会报错重复创建
别用
mysql -e "source backup.sql",这种写法不会自动识别
USE切库指令。
跳过某些表或忽略特定错误继续恢复
生产环境恢复常遇到表结构不一致、AUTO_INCREMENT 冲突或已存在数据的问题。硬扛着报错中断不如主动控制流程。
mysqldump备份阶段可用
--ignore-table=db_name.table_name排除个别大表(比如日志表);恢复阶段则靠
mysql的容错参数:
--force:遇到 SQL 错误(如主键冲突、字段类型不匹配)打印警告但继续执行
--init-command="SET FOREIGN_KEY_CHECKS=0;":关闭外键检查,避免因父表未导入导致子表建表失败 组合使用更稳妥:
mysql --force --init-command="SET FOREIGN_KEY_CHECKS=0;" myapp < backup.sql
注意:
--force不会跳过语法错误,只跳过运行时约束类错误;且它不记录哪些语句被跳过,建议先用
mysql --verbose测试一遍。
备份文件过大时的分卷与压缩处理
直接生成几百 MB 甚至 GB 级的 SQL 文件,不仅传输慢、编辑难,导入时还容易因超时或内存溢出失败。
推荐边 dump 边压缩,避免中间落盘大文件:
mysqldump --single-transaction --routines --triggers myapp | gzip > myapp_$(date +%F).sql.gz
恢复时解压直通:
zcat myapp_2024-06-15.sql.gz | mysql myapp
若需按表拆分,不用等 dump 完再切,而是用
--databases+ 循环遍历:
for db in $(mysql -Nse "SHOW DATABASES WHERE \`Database\` NOT IN ('information_schema','mysql','performance_schema','sys')"); do
mysqldump --single-transaction "$db" | gzip > "${db}_$(date +%F).sql.gz"
done
这种模式下每个库独立压缩,后续恢复更灵活,也方便并行导入。
真正麻烦的是字符集混用:如果源库用
utf8mb4,而目标 MySQL 配置里
character_set_server是
latin1,即使加了
--default-character-set=utf8mb4,也可能在恢复时出现乱码或截断。务必确认两端的
collation_connection和
character_set_client一致。
