ump 的备份是如何实现的,我们需要在 my.cnf 中的[mysqld] 参数段加入:
这样我们就可以通过观察 general.log 的输出,来了解 mysqldump 的备份是如何实现的。
1)--lock-tables 是如何实现的:
先执行:mysqldump -uroot -p --databases gs --lock-tables > gs_l.sql, 然后查看 general.log:
1> 第一步: SHOW CREATE DATABASE IF NOT EXISTS `gs`; 导出了建库语句;
2> 第二步:show tables; 获得数据库中所有表名,然后锁住:LOCK TABLES `tb1` READ /*!32311 LOCAL */,`user` READ /*!32311 LOCAL */
? ? ? ? ? ? ? ? 使用的是 lock table tb1 read local, tb2 read local, tb3 read local; 语句
3> 第三步:show create table 'tb1'; 导出了 tb1 的建表语句;
4> 第四步:show fields from `tb1`; SELECT /*!40001 SQL_NO_CACHE */ * FROM `tb1`; 导出了表中的数据;
......
5> 最后导出了 trigger, 最后的最后 unlock tables; 结束。
可以看到 --lock-tables 在导出一个数据库时,会在整个导出过程 lock read local 所有的表。该锁不会阻止其它session读和插入。
2)--lock-all-tables 的实现:
先执行:mysqldump -uroot -p --databases gs --lock-all-tables > gs_l.sql, 在查看 general.log:
它的实现使用了 FLUSH TABLES; FLUSH TABLES WITH READ LOCK; 语句。在最后没有看到解锁语句。
它请求发起一个全局的读锁,会阻止对所有表的写入操作,以此来确保数据的一致性。备份完成后,该会话断开,会自动解锁。
3)--single-transaction 的实现:
先执行:?mysqldump -uroot -p --databases gs --single-transaction > gs_l.sql,在查看 general.log:
基本过程是:
1> 先改变事务隔离级别:SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ
2> 开始事务:START TRANSACTION /*!40100 WITH CONSISTENT SNAPSHOT */
3> unlock tables;
4> 导出建库语句; SHOW CREATE DATABASE IF NOT EXISTS `gs`
5> 打开一个 savepoint: SAVEPOINT sp;
6> 导出 表 tb1 的结构和数据;
7> ROLLBACK TO SAVEPOINT sp; 回滚到savepoint;
对其它表重复该过程;
8> 最后 realease savepoint p; 释放savepoint;
整个过程,没有任何锁。RR隔离级别保证在事务中只读取本事务之前的一致性的数据。 rollback to savepoint sp; 保证了对数据库中的数据没有影响。
4)--master-data 的实现:
先执行:mysqldump -uroot -p --databases gs --master-data=1 > gs_l.sql,在查看general.log:
发现了 --lock-all-tables一样,就多了一句:show master status;
5)--single-transaction 和 --master-data 结合使用:
先执行:mysqldump -uroot -p --databases gs --master-data=1 > gs_l.sql,在查看general.log:
发现 --single-transaction 单独使用 与 --single-transaction 和 --master-data 结合使用 的区别如下图:

--single-transaction 和 --master-data 结合使用时,在导出开始,会短暂的持有一个全局的读锁,锁定时:刷新数据到磁盘、设置隔离级别为RR、开始事务、输出 binary log 的位置和文件名,然后解锁。这样就保证了:show master status 输出的 binary log 的位置和文件名 和 后面 导出的数据是同一个时间点的(同一个lsn),所以才能使用该备份 和 利用 change master to 构造一个 slave,成功的连接上 master.
可以看到这里使用了两次 flush tables:
FLUSH /*! 40101 LOCAL */ TABLES
FLUSH TABLES WITH READ LOCK
其原因是 第一次 flush 是不需要锁表的,第一次将所有数据刷新到磁盘之后,第二次 FLUSH TABLES WITH READ LOCK 时就会只有很少量的数据需要刷新到磁盘,所以第一次 flush 是为了尽量的 减少 第二次? fush 持有锁的时间。
11. mysqldump 与 锁
1)--lock-tables 会在整个导出过程 lock read local 所有的表。该锁不会阻止其它session读和插入,但是显然阻塞了update。
2)--lock-all-tables 它请求发起一个全局的读锁,会阻止对所有表的写入操作(insert,update,delete),以此来确保数据的一致性。备份完成后,该会话断开,会自动解锁。
?
3)--single-transaction 和 --master-data 结合使用时,也是在开始时,会短暂的请求一个全局的读锁,会阻止对所有表的写入操作。
4)--single-transaction 单独使用,不会有任何锁。但是测试表明: 它也需要对备份的表持有 metadata lock 的共享锁。
而我们知道,一般的事务,持有的是 行锁,还有 metadata lock 的共享锁。所以实际上,mysqldump不论你使用哪些选项,都不会阻塞事务的执行。
因为它们对锁的申请,没有任何排它性。而不像DDL一样需要持有 metadata lock 上的独占锁(排它锁)。当然DDL也会阻塞mysqldump。
mysqldump 一定需要表上的 metadata lock 共享锁。然后,要么需要所有备份表上的local读锁(lock table tb1 read local),要么需要的是所有备份表上的全局读锁(FLUSH TABLES WITH READ LOCK;)。