mysqldump --single-transaction仅对innodb表有效,依赖repeatable read隔离级别、无ddl操作、无长事务阻塞;myisam或混合引擎库会失效,需改用--lock-all-tables或统一引擎。

能保持,但仅限InnoDB表,且必须满足REPEATABLE READ隔离级别、无DDL操作、无长事务阻塞这几个硬条件;MyISAM或混合引擎库直接失效。
mysqldump --single-transaction 为什么只对 InnoDB 有效
它本质是靠 InnoDB 的 MVCC 快照机制:启动一个 START TRANSACTION WITH CONSISTENT SNAPSHOT,后续所有 SELECT 都基于同一时间点的版本视图。MyISAM 没有 Undo Log 和多版本,--single-transaction 对它完全不生效——既不加锁,也不建快照,备份过程可能跨多个时间点,导致订单表和用户表数据错位。
常见错误现象:mysqldump 执行成功,但恢复后外键关联断裂(比如订单里 user_id=1001,用户表却查不到),往往就是混用了 MyISAM 表,或备份中途执行了 ALTER TABLE。
- 务必提前检查:
SELECT table_name, engine FROM information_schema.tables WHERE table_schema = 'your_db'; - 混合引擎库不能只靠
--single-transaction,得用--lock-all-tables或分表处理 - MySQL 5.7+ 默认隔离级别是
REPEATABLE READ,但脚本中显式加SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;更稳妥
备份期间哪些操作会破坏一致性
--single-transaction 的快照不是“一劳永逸”的。一旦备份过程中发生隐式提交(implicit commit),当前事务就自动结束,后续读取将看到新状态,快照失效。
典型破坏行为包括:ALTER TABLE、DROP DATABASE、RENAME TABLE、ANALYZE TABLE、CREATE INDEX 等 DDL。mysqldump 检测到这类操作会报错退出:mysqldump: Got error: 1412: Table definition has changed, please retry transaction。
- 长事务也会卡住快照建立:执行
SHOW PROCESSLIST,若看到大量Waiting for table flush,说明已有未提交事务运行超 60 秒,需先 kill 或等待其结束 - autocommit=1 时,每个语句都是独立事务,
--single-transaction失效——确认SELECT @@autocommit;返回 0 - 不要在备份窗口内做任何结构变更,哪怕只是加个字段
为什么 --master-data=2 不是可选项而是必选项
--single-transaction 只管“逻辑时间点一致”,不管“物理日志位置”。没有 --master-data=2,备份文件里不记录 binlog 坐标,你无法做时间点恢复(PITR)。恢复完 SQL 后,只能从备份那一刻起全量重跑业务,中间所有变更全丢。
它会在 dump 文件头部插入类似这样的注释:-- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000001', MASTER_LOG_POS=12345;。这个位置是备份开始时刻的 binlog 位点,不是结束时刻。
- 搭配使用才是完整方案:
mysqldump --single-transaction --master-data=2 --routines --triggers -u root -p mydb > backup.sql - 如果用
mysqlpump,它不支持--master-data,必须额外执行SHOW MASTER STATUS手动记录 - GTID 环境下,
--set-gtid-purged=ON替代--master-data,但同样不可省略
真正强一致的兜底方案:FLUSH TABLES WITH READ LOCK
当你要备份 MyISAM 表、或跨引擎、或需要 100% 确保物理+逻辑双一致时,FLUSH TABLES WITH READ LOCK 是唯一可靠选择。它会全局阻塞所有写入(DML + DDL),直到你执行 UNLOCK TABLES 或连接断开。
但它不是“按一下就完事”。执行后立刻查 SHOW PROCESSLIST,若看到大量线程卡在 Waiting for table flush,说明已有长查询或未提交事务正占用表,此时锁根本没生效,dump 出来仍是脏的。
- 务必配合
SHOW MASTER STATUS记录 binlog 位点,否则锁释放后的变更无法追回 - 不能依赖 sleep 自动解锁——网络抖动或脚本异常会导致锁长期残留,压垮线上服务
-
mysqldump --lock-all-tables底层就是它,但比手动更危险:dump 进程崩溃,锁不会自动释放
复杂点在于:一致性从来不是单个参数的事。它取决于引擎类型、事务状态、binlog 配置、甚至备份时有没有人顺手改了表结构。最容易被忽略的是——你确认了 InnoDB,却忘了数据库里还有个 archive_log 表是 Archive 引擎,或者某个监控脚本每分钟执行一次 OPTIMIZE TABLE。











