有个数据迁移的需求,需要将A数据库的数据迁移至数据库B。
我以为直接生成mysqldump脚本再跑一下就行了,但是发现并不行。
问题出在java.lang.Runtime类上。
Runtime.exec()备份MySQL数据库的问题
概括说就是,使用时应该先将指令写入一个文件,使用exec(String command)时,在具体command中执行文件。
//生成指令,指令写入文件
Process p = Runtime.getRuntime().exec("./command.sh");
//获取输入流,查看运行状态等等
解决执行指令问题后,另一个问题出现了,
[Warning] Using a password on the command line interface can be insecure.
当执行的指令中包含明文密码时,会报警告。
[Warning] Using a password on the command line interface can be insecure.
我参考了这篇文章,可以解决问题。
但是后来使用中发现其实并不影响执行指令,出于省事的角度考虑,我就把它输出到一个warn.log文件中就不管了。
贴一下主要的代码
组合mysqldump指令
/**
* mysqldump -h 1.1.1.1 -P3306 -uroot -proot -C --set-gtid-purged=OFF --databases db1|mysql -h 1.1.1.2 -P3306 -uroot -proot --database db1
*
* @return
*/
public String getDumpCommand() {
StringBuilder dump = new StringBuilder();
dump.append("mysqldump -h").append(sourceIP).append(" -P").append(sourcePort).append(" -u").append(sourceUsername).append(" -p").append(sourcePassword.replace("!", "\\!")).append(" -C --set-gtid-purged=OFF --databases ").append(sourceDatabase).append(" |mysql -h ").append(targetIP).append(" -P").append(targetPort).append(" -u").append(targetUsername).append(" -p").append(targetPassword.replace("!", "\\!")).append(" --database ").append(targetDatabase);
return dump.toString();
}
执行update脚本
/**
* 语法格式:mysql -h ip -u userName -p -D dbName < sqlFilePath(最后没有分号)
* -h:数据库所在的主机。如果是本机,可以使用localhost,或者省略此项
* -u:连接数据库用户名
* -p:连接数据库密码
* dbName:要使用的具体的某个数据库。如果sql脚本中没有使用“use dbName”选择数据库,则此处必须定制数据库;如果使用了则和可以省略
* sqlFilePath : sql脚本的路径。如我将sql脚本放在了D盘,我的sql脚本的名字是”test_sql.sql”。则路径为”D:\test_sql.sql”。
*
* @return
*/
public String getImportCommand(File filePath) {
StringBuilder command = new StringBuilder();
command.append("mysql -h").append(sourceIP).append(" -P").append(sourcePort).append(" -u").append(sourceUsername).append(" -p").append(sourcePassword.replace("!", "\\!")).append(" -D").append(sourceDatabase).append(" < ").append(filePath.getAbsolutePath());
return command.toString();
}
public String execCommand() {
log.info("脚本迁移启动");
long t1 = System.currentTimeMillis();
//这一行生成需要执行的指令
List<String> command = getSpecifiedCommand();
//指令写到shell中
File shell = new File("command.sh");
if (!shell.exists()) {
try {
shell.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
FileWriter fw = null;
BufferedWriter bw = null;
try {
fw = new FileWriter(shell);
bw = new BufferedWriter(fw);
for (String s : command) {
bw.write(s);
bw.newLine();
bw.flush();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fw.close();
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
try {
log.info("************开始执行sql脚本************");
Runtime.getRuntime().exec("chmod 777 command.sh");
Process p = Runtime.getRuntime().exec("./command.sh");
BufferedReader errorResultReader = null;
BufferedReader infoResultReader = null;
errorResultReader = new BufferedReader(new InputStreamReader(p.getErrorStream()));
infoResultReader = new BufferedReader(new InputStreamReader(p.getInputStream()));
String infoLine;
while ((infoLine = infoResultReader.readLine()) != null) {
//log.info("脚本文件执行信息:{}", infoLine);
}
String errorLine;
while ((errorLine = errorResultReader.readLine()) != null) {
log.debug("脚本文件执行异常:{}", errorLine);
}
// 等待程序执行结束并输出状态
int exitCode = p.waitFor();
if (0 == exitCode) {
//log.info("脚本文件执行成功:" + exitCode);
} else {
//log.error("脚本文件执行失败:" + exitCode);
}
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("************sql脚本执行结束************");
long t2 = System.currentTimeMillis();
log.info("脚本迁移结束,用时:" + (t2 - t1) + " 毫秒");
return "";
}