mysqldump --single-transaction 能不锁表又保证一致性,本质是开启 REPEATABLE READ 事务并执行 START TRANSACTION WITH CONSISTENT SNAPSHOT,基于 InnoDB MVCC 获取时间点快照;--master-data=2 则通过短暂内部操作获取并注释记录 Binlog 位点,两者协同实现无锁且一致的备份。

可以,但必须满足两个前提:主库启用了 binlog 且使用 ROW 格式,同时表有主键或唯一非空索引。不锁表 ≠ 不一致,关键在于用 --single-transaction 拿到一致性快照,再靠 --master-data=2 绑定精确位点。
为什么 mysqldump --single-transaction 能不锁表又保证一致性
--single-transaction 的本质是开启一个 REPEATABLE READ 事务,在 dump 开始时执行一次 START TRANSACTION WITH CONSISTENT SNAPSHOT。此后所有表读取都基于这个快照,不受后续写入影响。它不要求全局锁,但要求存储引擎支持 MVCC(InnoDB 可以,MyISAM 不行)。
常见错误现象:mysqldump: Got error: 1146: Table 'xxx' doesn't exist when using LOCK TABLES —— 这通常是因为某个表是 MyISAM,或事务中 DDL 改了表结构导致快照失效。
- 仅对 InnoDB 表生效;混合引擎库需额外处理 MyISAM 表(要么转成 InnoDB,要么单独锁表导出)
- dump 过程中不能有
DROP/ALTER TABLE,否则事务会中断并报错 - 如果主库
binlog_format是MIXED或STATEMENT,某些语句可能无法被从库安全重放,建议提前设为ROW
--master-data=2 是怎么自动带出 binlog 位置的
--master-data=2 会在导出 SQL 文件开头插入一条带注释的 CHANGE MASTER TO 语句,例如:
-- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000042', MASTER_LOG_POS=19876543;
这个位置不是 dump 开始时的位点,而是执行 FLUSH TABLES WITH READ LOCK(内部短暂触发)后立刻查的 SHOW MASTER STATUS 结果 —— 但它**不真正加锁**,只在极短时间内获取位点,所以对外表现为“无锁”。
容易踩的坑:
- 如果 dump 前主库刚重启过,
binlog文件可能还没轮转,但MASTER_LOG_POS会从 154(MySQL 8.0+)或 4(旧版)开始,不是 0 - 若导出时主库压力大、事务长,
--single-transaction可能等很久才拿到快照,导致 dump 时间变长,但不会阻塞业务写入 - 文件里那条注释是纯文本,导入从库前要手动提取出来,不能直接靠
source执行(它只是注释,不生效)
从库导入后怎么设置正确的复制起点
导入 full_dump.sql 后,不能直接用文件里的注释启动复制,因为导入本身会产生新 binlog 事件,从库的 relay_log 位置已变。正确做法是:导入完成后,立即在从库上执行 CHANGE MASTER TO,其中 MASTER_LOG_FILE 和 MASTER_LOG_POS 必须严格使用 dump 文件开头注释里的值。
示例操作链:
mysql -u root -p < full_dump.sql<br>mysql> STOP SLAVE;<br>mysql> CHANGE MASTER TO MASTER_HOST='10.10.1.100', MASTER_USER='repl', MASTER_PASSWORD='xxx', MASTER_PORT=3306, MASTER_LOG_FILE='mysql-bin.000042', MASTER_LOG_POS=19876543;<br>mysql> START SLAVE;
关键注意点:
- 导入过程必须在
STOP SLAVE之后、CHANGE MASTER TO之前完成;中间不能有其他写入 - 如果从库之前有数据,务必先清空(
DROP DATABASE或重置datadir),否则主键冲突会导致START SLAVE失败 -
MASTER_LOG_POS是主库的位点,不是从库的Exec_Master_Log_Pos,别混淆
真正容易被忽略的是:即使全程没锁表,只要 dump 过程中主库有大事务未提交,--single-transaction 就会等待它结束才能拿到快照 —— 这时候你看到的是“没锁表”,但实际业务写入被间接延迟了。所以不锁表不是银弹,得看主库当时的事务负载。


















