Java执行多表带条件的mysqldump命令时,第二个追加导出命令无效问题求助
Java执行多表带条件的mysqldump命令时,第二个追加导出命令无效问题求助
嘿,我帮你排查下这个问题——你的代码里有两个关键原因导致第二条追加备份的命令没生效,先来看下你的代码:
String executeCmd1 = ""; String executeCmd2 = ""; executeCmd1 = "C:/wamp64/bin/mysql/mysql5.7.14/bin/mysqldump -u "+dbUser+" -p"+dbPass+" "+dbName+" "+dbTable+" --where=id="+whereStatement+" --single-transaction --skip-lock-tables --no-create-info -r D:/backup.sql"; executeCmd2 = "C:/wamp64/bin/mysql/mysql5.7.14/bin/mysqldump -u "+dbUser+" -p"+dbPass+" "+dbName+" "+dbTable_1+" --where=course_id="+whereStatement+" --single-transaction --skip-lock-tables --no-create-info >> D:/backup.sql"; System.out.println(executeCmd1); System.out.println(executeCmd2); Process runtimeProcess =Runtime.getRuntime().exec(executeCmd1); int processComplete = runtimeProcess.waitFor(); if(processComplete == 0){ System.out.println("Backup taken successfully"); Process runtimeProcess1 =Runtime.getRuntime().exec(executeCmd2); int processComplete1 = runtimeProcess.waitFor(); // 这里踩坑了! } else { System.out.println("Could not take mysql backup"); }
问题1:等待了错误的进程
你执行完第二条命令后,调用的是runtimeProcess.waitFor()——也就是还在等待第一个备份进程结束,而不是第二个新创建的runtimeProcess1。这会导致第二个进程的执行状态完全没被正确等待和检查,甚至可能因为资源未释放而静默失败。
问题2:Runtime.exec()不支持Shell的重定向符号>>
这才是核心问题!第一条命令用了mysqldump自带的-r参数指定输出文件,所以能正常工作;但第二条命令里的>>是Shell(比如Windows的cmd)特有的追加语法,而Runtime.exec()是直接调用可执行程序,不会通过Shell解析命令,所以这个>>会被当成普通参数传给mysqldump,自然不会产生追加文件的效果。
给你两个可行的修正方案
方案一:通过Java流捕获输出并追加(推荐,跨平台)
我们可以去掉第二条命令里的>>,转而用Java的输入输出流把mysqldump的输出追加到目标文件,同时修正进程等待的问题:
// 第一条命令保持不变,用-r直接输出到文件 Process runtimeProcess = Runtime.getRuntime().exec(executeCmd1); int processComplete = runtimeProcess.waitFor(); if (processComplete == 0) { System.out.println("第一个表备份成功"); // 把第二条命令拆分成字符串数组,避免特殊字符解析问题 String[] cmd2Args = { "C:/wamp64/bin/mysql/mysql5.7.14/bin/mysqldump", "-u", dbUser, "-p" + dbPass, dbName, dbTable_1, "--where=course_id=" + whereStatement, "--single-transaction", "--skip-lock-tables", "--no-create-info" }; Process runtimeProcess1 = Runtime.getRuntime().exec(cmd2Args); // 捕获mysqldump的输出,追加到backup.sql try (InputStream cmdOutput = runtimeProcess1.getInputStream(); FileOutputStream fileOut = new FileOutputStream("D:/backup.sql", true)) { byte[] buffer = new byte[1024]; int bytesRead; while ((bytesRead = cmdOutput.read(buffer)) != -1) { fileOut.write(buffer, 0, bytesRead); } } // 等待第二个进程完成,并检查执行状态 int processComplete1 = runtimeProcess1.waitFor(); if (processComplete1 == 0) { System.out.println("第二个表追加备份成功"); } else { System.out.println("第二个表备份失败,错误信息:"); // 读取错误流排查问题,这一步非常重要! try (InputStream errStream = runtimeProcess1.getErrorStream()) { System.out.println(new String(errStream.readAllBytes())); } } } else { System.out.println("第一个表备份失败,错误信息:"); try (InputStream errStream = runtimeProcess.getErrorStream()) { System.out.println(new String(errStream.readAllBytes())); } }
方案二:通过Windows的cmd.exe执行命令(仅Windows环境)
如果你的程序只在Windows上运行,可以把第二条命令用cmd.exe /c包裹,让Shell来解析>>符号:
if(processComplete == 0){ System.out.println("Backup taken successfully"); // 用cmd.exe来执行带重定向的命令 String fullCmd2 = "cmd.exe /c \"" + executeCmd2 + "\""; Process runtimeProcess1 = Runtime.getRuntime().exec(fullCmd2); // 等待第二个进程完成 int processComplete1 = runtimeProcess1.waitFor(); if (processComplete1 == 0) { System.out.println("第二个表追加备份成功"); } else { System.out.println("第二个表备份失败"); // 同样建议读取错误流排查问题 } }
额外提醒
- 一定要处理进程的错误流!很多时候命令执行失败是因为有错误输出,但如果不读取错误流,进程会因为缓冲区满而阻塞,导致看似没执行的情况。
- 直接在命令行拼接密码有安全风险,建议改用
--defaults-extra-file参数指定包含用户名密码的配置文件,避免密码泄露。 - 把命令拆分成字符串数组(方案一的写法)能避免因为用户名、密码或数据库名里有空格等特殊字符导致的命令解析错误。
备注:内容来源于stack exchange,提问作者Ganesh Thandapani
相关产品推荐
相关产品推荐

