首先我们把参数和内部变量对应起来,并且看一下它们的注释:
–single-transaction: opt_single_transaction–master-data: opt_master_data–lock-all-tables: opt_lock_all_tables–lock-tables: lock_tables–flush-logs: flush_logs–delete-master-logs: opt_delete_master_logs–apply-slave-statements: opt_slave_apply(5.5)主要代码流程我们分别看一下5.1和5.5的代码,都基于最新的trunk(5.1-rev.3909; 5.5-rev.4148)。
5.1版本主要流程我们首先看下5.1版本的。
5320 if ((opt_lock_all_tables || opt_master_data) && 5321 do_flush_tables_read_lock(mysql)) 5322 goto err; |
如果设置了master-data或lock-all-tables,则做FLUSH TABLES的操作。
来看下do_flush_tables_read_lock()里面是怎么做的,
do_flush_tables_read_lock() 4665 return 4666 ( mysql_query_with_error_report(mysql_con, 0, 4667 ((opt_master_data != 0) ? // 如果设置了--master-data 4668 "FLUSH /*!40101 LOCAL */ TABLES" : // 那么用FLUSH LOCAL TABLES 4669 "FLUSH TABLES")) || // 如果没设置那么使用FLUSH TABLE 4670 mysql_query_with_error_report(mysql_con, 0, 4671 "FLUSH TABLES WITH READ LOCK") ); // 如果上面的语句执行成功了,再执行这个 |
先FLUSH TABLES,成功后用FLUSH TABLES WITH READ LOCK加全局读锁。
再往下会判断single-transaction,
5323 if (opt_single_transaction && start_transaction(mysql)) 5324 goto err; |
如果定义了–single-transaction则打开一个事务来读取数据。
我们看下start_transaction()的实现,
start_transaction() 4741 return (mysql_query_with_error_report(mysql_con, 0, 4742 "SET SESSION TRANSACTION ISOLATION " 4743 "LEVEL REPEATABLE READ") || // 先设置会话的隔离级别为RR 4744 mysql_query_with_error_report(mysql_con, 0, 4745 "START TRANSACTION " 4746 "/*!40100 WITH CONSISTENT SNAPSHOT */")); // 再用一致性快照模式(RR)启动事务 |
会先设置隔离级别为RR,然后START TRANSACTION加上一致性快照的Hint。
接下来是获取Master的状态,
5338 if (opt_master_data && do_show_master_status(mysql)) 5339 goto err; |
如果设置了–master-data 则把当前的Master status打印出来。
接下来再判断如果启用了–single-transaction,则可以释放表锁的,因为事务已经启动了。
5340 if (opt_single_transaction && do_unlock_tables(mysql)) /* unlock but no commit! */ 5341 goto err; |
do_unlock_tables()里面就发一条UNLOCK TABLES语句释放全局表锁。
do_unlock_tables() 4677 return mysql_query_with_error_report(mysql_con, 0, "UNLOCK TABLES"); |
然后开始调用dump_*函数根据需要导出整个实例或者一个库或者一个表。
dump_all_databases()->dump_all_tables_in_db() 4307 if (lock_tables) 4308 { 4309 DYNAMIC_STRING query; 4310 init_dynamic_string_checked(&query, "LOCK TABLES ", 256, 1024); 4311 for (numrows= 0 ; (table= getTableName(1)) ; ) 4312 { 4313 char *end= strmov(afterdot, table); 4314 if (include_table((uchar*) hash_key,end - hash_key)) 4315 { 4316 numrows++; 4317 dynstr_append_checked(&query, quote_name(table, table_buff, 1)); 4318 dynstr_append_checked(&query, " READ /*!32311 LOCAL */,"); 4319 } 4320 } 4321 if (numrows && mysql_real_query(mysql, query.str, query.length-1)) 4322 DB_error(mysql, "when using LOCK TABLES"); 4323 /* We shall continue here, if --force was given */ 4324 dynstr_free(&query); 4325 } /* 如果设置了--lock-tables(默认),则导出之前需要LOCK TABLES tables_name READ。*/ ... 4332 while ((table= getTableName(0))) 4333 { 4334 char *end= strmov(afterdot, table); 4335 if (include_table((uchar*) hash_key, end - hash_key)) 4336 { 4337 dump_table(table,database); // 导出一张表 4338 my_free(order_by, MYF(MY_ALLOW_ZERO_PTR)); 4339 order_by= 0; 4340 if (opt_dump_triggers && mysql_get_server_version(mysql) >= 50009) 4341 { 4342 if (dump_triggers_for_table(table, database)) // 导出 trigger 4343 { 4344 if (path) 4345 my_fclose(md_result_file, MYF(MY_WME)); 4346 maybe_exit(EX_MYSQLERR); 4347 } 4348 } 4349 } 4350 } /* 先dump_table来导出表,然后再看是不是配置了--triggers来决定是不是导出Trigger,dump_triggers_for_table。*/ ... 4366 if (lock_tables) 4367 VOID(mysql_query_with_error_report(mysql, 0, "UNLOCK TABLES")); /* 导出完成之后,释放表锁 */ |
所以我们可以知道,如果用–master-data和–single-transaction来导出数据,因为–lock-tables被自动关闭,所以导出过程中只会对当前正在做导出操作的表有IS锁,已经完成或没有开始的表,则不会加锁。
如果用的是默认–lock-tables打开的选项,则会先把所有库的锁加上,再进行导出操作,最后一次性释放所有锁。
接下来我们再比较一下,5.5的mysqldump有哪些变化。
5464 if ((opt_lock_all_tables || opt_master_data || 5465 (opt_single_transaction && flush_logs)) && 5466 do_flush_tables_read_lock(mysql)) 5467 goto err; |
这里有所不同,增加了flush_logs的判断,如果只是单纯的–single-transaction,不会调用do_flush_tables_read_lock(),必须同时制定–flush-logs。
5469 /*5470 Flush logs before starting transaction since5471 this causes implicit commit starting mysql-5.5.5472 */ 5473 if (opt_lock_all_tables || opt_master_data || 5474 (opt_single_transaction && flush_logs) || 5475 opt_delete_master_logs) 5476 { 5477 if (flush_logs || opt_delete_master_logs) 5478 { 5479 if (mysql_refresh(mysql, REFRESH_LOG)) 5480 goto err; 5481 verbose_msg("-- main : logs flushed successfully!\n"); 5482 } 5483 5484 /* Not anymore! That would not be sensible. */ 5485 flush_logs= 0; 5486 } |
5.5里面会尝试FLUSH LOGS。
5488 if (opt_delete_master_logs) 5489 { 5490 if (get_bin_log_name(mysql, bin_log_name, sizeof(bin_log_name))) 5491 goto err; 5492 } |
5.5新增的变量,删除master上的log,这里先获取binlog的文件名。
5494 if (opt_single_transaction && start_transaction(mysql)) 5495 goto err; |
这一段没有变化
5497 /* Add 'STOP SLAVE to beginning of dump */ 5498 if (opt_slave_apply && add_stop_slave()) 5499 goto err; 5500 if (opt_master_data && do_show_master_status(mysql)) 5501 goto err; 5502 if (opt_slave_data && do_show_slave_status(mysql)) 5503 goto err; 5504 if (opt_single_transaction && do_unlock_tables(mysql)) /* unlock but no commit! */ 5505 goto err; |
这里有新加的opt_slave_apply和opt_slave_data部分,添加STOP SLAVE语句和显示SHOW SALVE STATUS的结果。
之后也是调用dump_*来导出数据。
但是因为5.5有了MDL(Meta data lock),所以–single-transaction时,事务内操作过的表都会持有MDL,因此不会被DDL破坏。
例如,mysqldump已经备份了a,b,c表,因为它们在事务内,事务还没提交,它们的MDL不会释放,因此另外的线程如果做a,b,c中任意一张表的DDL操作,都会出现Waiting for table metadata lock,而还没备份到的表不会持有MDL,因此还可以做DDL。
上一篇:怎么解决mysql数据库IP address could not be resolved报错问题
下一篇:Mysql SSD压力测试分析
mysqldump









