🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
## 背景 用户在使用mysqldump导数据上云的时候碰到两个“诡异”的问题,简单分析分享下。 ## TIP 1 --port端口无效? 本地有3306和3307两个端口的实例,执行命令为: ~~~ mysqldump --host=localhost --port=300x -Ddb1 db1 -r outputfile ~~~ 发现无论执行端口写入3306还是3307,导出的都是3306端口实例的数据。 ## 代码分析 实际上不论是mysqldump还是mysql客户端,在连接数据库时都调用了 `CLI_MYSQL_REAL_CONNECT` 这个函数,里面的一段代码逻辑如下 ~~~ if(!host || !strcmp(host,LOCAL_HOST) { vio_socket_connect(... } 其中 #define LOCAL_HOST "localhost" ~~~ 也就是说,当host参数值为localhost的时候,mysql和mysqldump客户端使用的是–socket参数,如果未指定,则使用默认的/tmp/mysql.sock。 因此上面用户的输入,不论–port 输入多少,都被忽略。而他的/tmp/mysql.sock 就是属于3306端口实例。 从代码中可以看到,必须是全小写的localhost才满足条件,若是Localhost,则解析成127.0.0.1,用的是 ip + port 的模式,此时 –socket 参数无效。 ## TIP 2 导出的数据无法导入? 使用mysqldump默认参数导出5.6 的数据,无法导入到目标库。 当源库使用了GTID模式时,在dump出来的文件中为了保持目标库和源库GTID值相同,增加了两个语句, `SET @@SESSION.SQL_LOG_BIN= 0` 和 `SET @@GLOBAL.GTID_PURGED='xxxx'`。 而实际上增加这两个语句会有诸多问题: 1. 关闭binlog首先需要super权限,如果目标库只能使用普通账号,则会导致执行失败; 2. 即使有super权限,也会导致这些操作不记录到binlog,会导致主备不一致。当然也可以说,这就要求同一份dump要restore到目标库的主库和所有备库才能保持主备一致; 3. `SET @@GLOBAL.GTID_PURGED='xxxx'`这个命令要求目标库的`gtid_executed`值是空。若非空,这个命令执行失败; 4. reset master可以清空`gtid_executed`值,也需要super权限。 因此在导出5.6的数据时,有两种可选方案: 1. 在有目标库的super权限时,用默认dump参数,在导入到目标库之前,先执行reset master;这样需要在主库和所有备库都执行相同个导入动作; 2. mysqldump需要增加参数 –set-gtid-purged=off,这样不会生成上述两个语句,数据能够直接导入。但是目标库的gtid set就与源库不同。 需要根据业务需求选择。