mysql数据库备份
文章目录
- 一、背景
- 二、代码
- DatabaseManageControl
- DatabaseManageUserControl
- ConfigValue
- DataServiceConfigValue
- application.properties
- application-cvt.properties
- application-xpt.properties
- CommonUtil
- QueryBackupDatabaseParams
- FileUtils
- ClientService
- ClientServiceI
- DataBaseServImpl
- SystemDao
- SystemDaoImpl
- 三、说明
- 四、错误场景
- 错误场景1:java执行cmd命令方式有3种
- 错误场景2:java.io.IOException: Cannot run program "cd /d C:\Program Files (x86)\xnms-install\cvt-windows-service\..\mysql\bin\": CreateProcess error=2, 系统找不到指定的文件。
- 错误场景3:备份命令是否带空格
- 错误场景4:'C:\Program' 不是内部或外部命令,也不是可运行的程序或批处理文件。
- 错误场景5:mysqldump: Got error: 1049: Unknown database 'files' when selecting the database
- 五、总结
一、背景
项目针对Mysql某个数据库进行压缩,这里的压缩指代“逻辑压缩”,备份结果是个xx.sql文件。
MySQL备份的执行流程(以逻辑备份和物理备份为例)
备份主要分为两大类:逻辑备份 和 物理备份。它们的执行流程有所不同。
逻辑备份
逻辑备份就像是给数据库“拍照”,保存的是数据库的逻辑结构(CREATE DATABASE, CREATE TABLE语句)和数据(INSERT语句)。最常见的工具是 mysqldump。
执行流程(以 mysqldump
为例):
-
连接数据库
:使用授权的账号密码连接到MySQL实例。 -
刷新日志与锁表
(关键步骤):-
备份工具会请求数据库刷新日志,并开启一个一致性快照。
-
对于支持事务的存储引擎(如InnoDB),mysqldump 默认使用 --single-transaction 参数。它通过启动一个事务,利用MVCC(多版本并发控制)来获取一个一致性的数据快照。在这个过程中,不需要锁表,数据库可以正常读写。
-
对于非事务引擎(如MyISAM),为了保持数据一致性,它需要对所有表加读锁。在加锁期间,其他会话的写操作(INSERT, UPDATE, DELETE)会被阻塞,直到锁释放。这会影响业务,因此建议避免在生产环境使用非事务引擎。
-
-
逐表读取数据
:根据上一步获得的一致性视图,逐个读取表的结构和数据。 -
生成SQL文件
:将读取到的信息转换成SQL语句,写入到备份文件中。 -
释放资源
:备份完成,释放事务或锁。 -
记录Binlog位置(如果指定了 --master-data 参数)
:在备份文件中记录下备份结束时二进制日志的位置,这对于后续搭建从库或做基于时间点的恢复至关重要。
优点
:备份文件是SQL,可读性强,可以在不同版本的MySQL之间迁移,恢复粒度可以到表级别。
缺点
:备份和恢复速度较慢(因为要执行SQL语句),对服务器性能有一定影响。
物理备份
物理备份就像是直接“复印”数据库的物理文件(数据文件、日志文件等)。最常见的工具是 Percona XtraBackup(适用于InnoDB/XtraDB引擎)。
执行流程(以 XtraBackup 为例):
-
开始备份
:启动备份进程。 -
拷贝数据文件
:-
并行地拷贝InnoDB的表空间文件(.ibd)和共享表空间文件(ibdata1)。
-
此阶段数据库可以正常读写。
-
-
记录LSN并锁表
:-
在拷贝完所有InnoDB文件后,XtraBackup会记录下此时的LSN(日志序列号)。
-
然后,它对非InnoDB表(如MyISAM)施加一个短暂的全局读锁(通常只有几秒钟)。
-
-
``拷贝其他文件`:在短暂的锁表期间,快速拷贝非InnoDB表的结构文件(.frm、.MYD等)、二进制日志位置信息等。
-
释放锁并结束备份
:释放全局读锁,备份完成。 -
准备备份
:-
由于备份过程中数据库仍在运行,拷贝的数据文件可能处于不一致的状态(例如,有部分数据在内存中还未写入文件)。
-
因此,需要一个 --prepare 步骤。这个步骤会应用备份过程中产生的重做日志(Redo Log),使备份数据文件达到一个逻辑上一致的状态,就像数据库在备份完成那个时间点被安全关闭了一样。
-
优点
:备份和恢复速度非常快(文件拷贝),对服务器性能影响小。
缺点
:备份文件大,不具可读性,通常不能跨版本或跨平台恢复。
关于“数据库压缩”
压缩通常在备份流程的最后一步进行,与备份类型无关。
逻辑备份压缩
:可以直接将 mysqldump 的输出通过管道传递给压缩工具。
bash
mysqldump -u root -p mydatabase | gzip > backup.sql.gz
物理备份压缩
:XtraBackup 自带压缩功能(–compress),也可以在备份完成后,使用操作系统命令对备份目录进行压缩。
二、代码
DatabaseManageControl
@Operation(summary = "数据库备份")
@GetMapping(value = "/backupDatabase")
public ResponseModel backupDatabase() {return databaseManageUserControl.backupDatabase();
}
DatabaseManageUserControl
@Autowired
private ConfigValue configValue;@Autowired
private DataServiceConfigValue dataServiceConfigValue;private static final SimpleDateFormat YMDHMS = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");public ResponseModel<String> backupDatabase() {try {QueryBackupDatabaseParams params = new QueryBackupDatabaseParams();String dSDataSource = configValue.obtainConfigValue("xnms.data.service.DSDataSource");String dSPort = configValue.obtainConfigValue("xnms.data.service.DSPort");String jdbcUrl = configValue.obtainConfigValue("spring.datasource.url");String[] jdbcUrlParse = FileUtils.parseJdbcUrl(jdbcUrl);if (jdbcUrlParse != null && jdbcUrlParse.length > 0) {params.setDataSource(jdbcUrlParse[0]);params.setdSPort(jdbcUrlParse[1]);if (!dSDataSource.equals(jdbcUrlParse[0])) {configValue.updateConfig("xnms.data.service.DSDataSource", jdbcUrlParse[0]);dataServiceConfigValue.writeConfig("xnms.data.service.DSDataSource", jdbcUrlParse[0]);}if (!dSPort.equals(jdbcUrlParse[1])) {configValue.updateConfig("xnms.data.service.DSPort", jdbcUrlParse[1]);dataServiceConfigValue.writeConfig("xnms.data.service.DSPort", jdbcUrlParse[1]);}}String userName = configValue.obtainConfigValue("spring.datasource.username");String password = configValue.obtainConfigValue("spring.datasource.password");String databaseName = configValue.obtainConfigValue("xnms.data.service.DSDatabaseName");String applicationPath = CommonUtil.getApplicationPath();File installDir = new File(applicationPath).getParentFile();String basePath = installDir.getAbsolutePath();String databaseBackupPath = basePath + configValue.obtainConfigValue("xnms.data.service.DBBackupPath");logger.info("databaseBackupPath:{}", databaseBackupPath);params.setUserName(userName);params.setPassword(password);params.setDatabaseName(databaseName);params.setDatabaseBackupPath(databaseBackupPath);params.setInstallBackupPath(basePath);File targetFile = new File(databaseBackupPath);if (!targetFile.exists()) {targetFile.mkdirs();}SingleResponse<Boolean> booleanSingleResponse = clientService.backupDatabase(params);Boolean isSuccess = booleanSingleResponse.getData();if (!isSuccess) {return ResponseModel.ofError(languageFind.findKey("BackupFailed"));}String dateFormat = YMDHMS.format(new Date());configValue.updateConfig("xnms.client.BackupDateTime", dateFormat);dataServiceConfigValue.writeConfig("xnms.client.BackupDateTime", dateFormat);Account account = (Account) SecurityUtils.getSubject().getPrincipal();clientService.clientLog(account.getUserName(), ClientLogType.LogDataBaseManager, ClientSubLogType.LogDataBaseManager_BackUpDB, "DatabaseBackupSuccess", account.getIp());} catch (Exception e) {logger.error("backupDatabase:{}", e.getMessage());}return ResponseModel.ofSuccess(languageFind.findKey("BackupSuccess"));
}
ConfigValue
@Autowired
private Environment env;@Autowired
private ApplicationContext applicationContext;@Autowired
private ApplicationContext applicationContext;public String obtainConfigValue(String key) {String configValue = "";try {configValue = env.getProperty(key);} catch (Exception ex) {logger.error("[XNMSProxyService] ObtainConfigValue :" + ex.getMessage(), ex);}return configValue;
}public String updateConfig(String key, String value) {// 获取 ConfigurableEnvironmentConfigurableEnvironment environment = (ConfigurableEnvironment) applicationContext.getEnvironment();// 更新动态配置的 MapdynamicConfigMap.put(key, value);// 使用自定义的 PropertySource 来存储动态配置PropertySource<?> propertySource = new org.springframework.core.env.MapPropertySource("dynamicConfig",dynamicConfigMap);environment.getPropertySources().remove("dynamicConfig");environment.getPropertySources().addFirst(propertySource);return "ok";
}
DataServiceConfigValue
@Autowired
private Environment env;@Autowired
private ApplicationContext applicationContext;public void writeConfig(String key, String value) {String workMode = env.getProperty("xnms.service.center.WorkMode");// 获取配置文件路径Resource resource = applicationContext.getResource("classpath:application.properties");if (Objects.equals(workMode, "0")) {resource = applicationContext.getResource("classpath:application-cvt.properties");}if (Objects.equals(workMode, "1")) {resource = applicationContext.getResource("classpath:application-xpt.properties");}// 用于存储文件原始内容List<String> lines = new ArrayList<>();try (InputStream inputStream = resource.getInputStream();BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {String line;while ((line = reader.readLine()) != null) {lines.add(line); // 保存每行内容}} catch (IOException e) {logger.error("ConfigService, writeConfig method, failed to read file:", e);return;}// 修改配置内容boolean keyFound = false;for (int i = 0; i < lines.size(); i++) {String line = lines.get(i).trim();// 跳过空行和注释行if (line.isEmpty() || line.startsWith("#")) {continue;}// 检查是否匹配到目标keyif (line.startsWith(key + "=")) {lines.set(i, key + "=" + value); // 修改指定键值对keyFound = true;break;}}if (keyFound) {try {// 获取文件的物理路径File file = resource.getFile();// 使用 FileWriter 覆盖原文件try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) {for (String line : lines) {writer.write(line);writer.newLine(); // 保证每行后面换行}writer.flush();}} catch (IOException e) {logger.error("ConfigService, writeConfig method, failed to write file:", e);}} else {logger.warn("没有找到指定的key: {}", key);}
}
application.properties
application-cvt.properties
xnms.service.center.WorkMode=0
xnms.client.BackupDateTime=
xnms.data.service.DBBackupPath=\\xnms-app\\mysqlBackup\\
xnms.data.service.DSDatabaseName=cvt_db
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://IP:13306/cvt_db
spring.datasource.username=root
spring.datasource.password=123456
xnms.client.BackupDateTime=
xnms.data.service.DSDataSource=localhost
xnms.data.service.DSPort=13306
xnms.data.service.DSDatabaseName=cvt_db
application-xpt.properties
xnms.service.center.WorkMode=1
xnms.client.BackupDateTime=
xnms.data.service.DBBackupPath=\\xnms-app\\mysqlBackup\\
xnms.data.service.DSDatabaseName=xpt_db
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://IP:13306/xpt_db
spring.datasource.username=root
spring.datasource.password=123456
xnms.client.BackupDateTime=
xnms.data.service.DSDataSource=localhost
xnms.data.service.DSPort=13306
xnms.data.service.DSDatabaseName=xpt_db
CommonUtil
/*** 获取应用路径** @return 应用路径*/
public static String getApplicationPath() {String baseFolder = "";try {baseFolder = new File("").getAbsolutePath(); // 获取当前工作目录} catch (Exception ex) {logger.error("<getApplicationPath> " + ex.getMessage(), ex);}return baseFolder;
}
QueryBackupDatabaseParams
package com.xnms.data.contract.database.db;import org.apache.commons.lang3.builder.ReflectionToStringBuilder;public class QueryBackupDatabaseParams {String dataSource;String dSPort;String userName;String password;String databaseName;String databaseBackupPath;String installBackupPath;public String getInstallBackupPath() {return installBackupPath;}public void setInstallBackupPath(String installBackupPath) {this.installBackupPath = installBackupPath;}public QueryBackupDatabaseParams() {}public String getDataSource() {return dataSource;}public void setDataSource(String dataSource) {this.dataSource = dataSource;}public String getUserName() {return userName;}public void setUserName(String userName) {this.userName = userName;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public String getDatabaseName() {return databaseName;}public void setDatabaseName(String databaseName) {this.databaseName = databaseName;}public String getDatabaseBackupPath() {return databaseBackupPath;}public void setDatabaseBackupPath(String databaseBackupPath) {this.databaseBackupPath = databaseBackupPath;}public String getdSPort() {return dSPort;}public void setdSPort(String dSPort) {this.dSPort = dSPort;}@Overridepublic String toString() {return ReflectionToStringBuilder.toString(this);}
}
FileUtils
public static String[] parseJdbcUrl(String jdbcUrl) {// 正则表达式匹配:jdbc:mysql://主机:端口/Pattern pattern = Pattern.compile("jdbc:mysql://([^:/]+):(\\d+)/");Matcher matcher = pattern.matcher(jdbcUrl);if (matcher.find()) {String host = matcher.group(1);String port = matcher.group(2);return new String[]{host, port};}return null;
}
ClientService
SingleResponse<Boolean> backupDatabase(QueryBackupDatabaseParams params);
ClientServiceI
@Override
public SingleResponse<Boolean> backupDatabase(QueryBackupDatabaseParams params) {SingleResponse<Boolean> singleResponse = new SingleResponse<>();try {singleResponse.setData(dataBase.backupDatabase(params));singleResponse.setSuccess(true);} catch (Exception ex) {logger.error("[DataBaseI] BackupDatabase error: " + ex.getMessage(), ex);singleResponse.setSuccess(false);singleResponse.setMsg(ex.getMessage());}return singleResponse;
}
DataBaseServImpl
public boolean backupDatabase(QueryBackupDatabaseParams params) {try {systemDao.backupDatabase(params); // 调用备份方法return true; // 备份成功} catch (Exception ex) {// 记录错误信息logger.error("[DataBaseServImpl] BackupDatabase: " + ex.getMessage() +(ex.getCause() != null ? "\n" + ex.getCause().getMessage() : ""), ex);return false; // 备份失败}
}
SystemDao
void backupDatabase(QueryBackupDatabaseParams params);
SystemDaoImpl
@Override
public void backupDatabase(QueryBackupDatabaseParams params) {try {List<String> cmds = new ArrayList<>();String fullPath = params.getInstallBackupPath() + "\\mysql\\bin\\mysqldump.exe";String dataSource = params.getDataSource();String dSPort = params.getdSPort();String userName = params.getUserName();String password = params.getPassword();String databaseName = params.getDatabaseName();String databaseBackupPath = params.getDatabaseBackupPath();String backupPath = databaseBackupPath + databaseName + "-" + dateFormat.format(new Date()) + ".sql";cmds.add("cmd");cmds.add("/c");cmds.add(fullPath);cmds.add("-h");cmds.add(dataSource);cmds.add("-P");cmds.add(dSPort);cmds.add("-u");cmds.add(userName);cmds.add("-p" + password);cmds.add("--databases");cmds.add(databaseName);runCmds(cmds, backupPath);} catch (Exception ex) {logger.error("<ServiceImpl backupDatabase> Error: {}", ex.getMessage(), ex);}
}private void runCmds(List<String> cmds, String backupPath) {try {ProcessBuilder processBuilder = new ProcessBuilder(cmds);processBuilder.redirectOutput(new File(backupPath));processBuilder.redirectErrorStream(true);Process process = processBuilder.start();int exitCode = process.waitFor();logger.info("Exit code: {}", exitCode);if (exitCode == 0) {logger.info("Backup successful: {}", backupPath);} else {logger.error("Backup failed with exit code: {}", exitCode);}} catch (Exception e) {logger.error("Error while running commands: {}", e.getMessage(), e);}
}
三、说明
说明点1
:上面看着比较多,实际大多都是无用的层级调,configValue和dataServiceConfigValue用于读取配置文件内容。
说明点2
:该备份为逻辑备份,而非物理备份。
四、错误场景
错误场景1:java执行cmd命令方式有3种
第1种:Method 1: Using cmd /c with full command string (Recommended)
private void executeCommandWithSpaces() {try {String fullCommand = "\"C:\\Program Files (x86)\\xnms-install\\mysql\\bin\\mysqldump.exe\" -h localhost -P 13306 -u root -p123456 --databases cvt_db > \"C:\\Program Files (x86)\\xnms-install\\xnms-app\\mysqlBackup\\backup.sql\"";ProcessBuilder processBuilder = new ProcessBuilder("cmd", "/c", fullCommand);Process process = processBuilder.start();// Read output streamBufferedReader outputReader = new BufferedReader(new InputStreamReader(process.getInputStream()));String outputLine;while ((outputLine = outputReader.readLine()) != null) {System.out.println("Output: " + outputLine);}// Read error streamBufferedReader errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));String errorLine;while ((errorLine = errorReader.readLine()) != null) {System.err.println("Error: " + errorLine);}int exitCode = process.waitFor();System.out.println("Exit code: " + exitCode);} catch (Exception e) {e.printStackTrace();}
}
第2种:Method 2: Using ProcessBuilder with individual arguments
private void executeCommandWithSpaces() {try {ProcessBuilder processBuilder = new ProcessBuilder("cmd", "/c","\"C:\\Program Files (x86)\\xnms-install\\mysql\\bin\\mysqldump.exe\"","-h", "localhost","-P", "13306", "-u", "root","-p123456","--databases", "cvt_db",">","\"C:\\Program Files (x86)\\xnms-install\\xnms-app\\mysqlBackup\\backup.sql\"");Process process = processBuilder.start();// Handle streamsBufferedReader outputReader = new BufferedReader(new InputStreamReader(process.getInputStream()));BufferedReader errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));String line;while ((line = outputReader.readLine()) != null) {System.out.println("Output: " + line);}while ((line = errorReader.readLine()) != null) {System.err.println("Error: " + line);}int exitCode = process.waitFor();System.out.println("Exit code: " + exitCode);} catch (Exception e) {e.printStackTrace();}
}
第3种:Method 3: Using Runtime.exec() with array
private void executeCommandWithSpaces() {try {String[] command = {"cmd", "/c","\"C:\\Program Files (x86)\\xnms-install\\mysql\\bin\\mysqldump.exe\" -h localhost -P 13306 -u root -p123456 --databases cvt_db > \"C:\\Program Files (x86)\\xnms-install\\xnms-app\\mysqlBackup\\backup.sql\""};Process process = Runtime.getRuntime().exec(command);// Handle streamsBufferedReader outputReader = new BufferedReader(new InputStreamReader(process.getInputStream()));BufferedReader errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));String line;while ((line = outputReader.readLine()) != null) {System.out.println("Output: " + line);}while ((line = errorReader.readLine()) != null) {System.err.println("Error: " + line);}int exitCode = process.waitFor();System.out.println("Exit code: " + exitCode);} catch (Exception e) {e.printStackTrace();}
}
错误场景2:java.io.IOException: Cannot run program “cd /d C:\Program Files (x86)\xnms-install\cvt-windows-service…\mysql\bin”: CreateProcess error=2, 系统找不到指定的文件。
2025-10-09 10:20:42.545 [http-nio-61000-exec-5] ERROR com.xnms.data.service.dao.mysql.impl.SystemDaoImpl - Error while running commands: Cannot run program "cd /d C:\Program Files (x86)\xnms-install\cvt-windows-service\..\mysql\bin\": CreateProcess error=2, 系统找不到指定的文件。
java.io.IOException: Cannot run program "cd /d C:\Program Files (x86)\xnms-install\cvt-windows-service\..\mysql\bin\": CreateProcess error=2, 系统找不到指定的文件。at java.base/java.lang.ProcessBuilder.start(ProcessBuilder.java:1143)at java.base/java.lang.ProcessBuilder.start(ProcessBuilder.java:1073)at com.xnms.data.service.dao.mysql.impl.SystemDaoImpl.runCmds(SystemDaoImpl.java:94)at com.xnms.data.service.dao.mysql.impl.SystemDaoImpl.backupDatabase(SystemDaoImpl.java:137)at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: java.io.IOException: CreateProcess error=2, 系统找不到指定的文件。at java.base/java.lang.ProcessImpl.create(Native Method)at java.base/java.lang.ProcessImpl.<init>(ProcessImpl.java:494)at java.base/java.lang.ProcessImpl.start(ProcessImpl.java:159)at java.base/java.lang.ProcessBuilder.start(ProcessBuilder.java:1110)... 100 common frames omitted
我的错误代码如下
private void runCmds(List<String> cmds) {try {ProcessBuilder processBuilder = new ProcessBuilder();processBuilder.command(cmds);Process process = processBuilder.start();// 输出命令的结果BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));String line;while ((line = reader.readLine()) != null) {logger.info("SystemDaoImpl类,runCmds方法:cmds = [{}]",line);}int exitCode = process.waitFor();if (exitCode != 0) {logger.error("Command execution failed with exit code: {}", exitCode);}} catch (Exception e) {logger.error("Error while running commands: {}", e.getMessage(), e);}}@Overridepublic void backupDatabase(QueryBackupDatabaseParams params) {try {List<String> cmds = new ArrayList<>();String applicationPath = CommonUtil.getApplicationPath();cmds.add("cd /d " + applicationPath);String dataSource = params.getDataSource();String dSPort = params.getdSPort();String userName = params.getUserName();String password = params.getPassword();String databaseName = params.getDatabaseName();String databaseBackupPath = params.getDatabaseBackupPath();String suffix = databaseName + " > " + databaseBackupPath + databaseName + "-" + dateFormat.format(new Date()) + ".sql";// 构建命令if (password == null || password.isEmpty()) {String cmd = String.format("MYSQLDUMP.exe -h %s -u %s --databases %s", dataSource, userName, suffix);logger.info("backupDatabase-cmd1:{}", cmd);cmds.add(cmd);} else {String cmd = String.format("MYSQLDUMP.exe -h %s -P %s -u %s -p%s --databases %s", dataSource, dSPort, userName, password, suffix);logger.info("backupDatabase-cmd2:{}", cmd);cmds.add(cmd);}runCmds(cmds);} catch (Exception ex) {logger.error("<ServiceImpl backupDatabase> Error: {}", ex.getMessage(), ex);}}
这个错误是因为在 Java 程序中直接执行 cd 命令导致的。cd 是 Windows 命令提示符的内部命令,不是独立的可执行程序。
问题分析
当 Java 的 Runtime.exec() 或 ProcessBuilder 尝试执行 cd 命令时,它会在系统 PATH 中查找名为 cd.exe 的可执行文件,但找不到,因为 cd 是 cmd 的内部命令。
解决方案
方法1:直接执行目标程序(推荐)
// 不要执行 cd 命令,直接执行 mysqldump 的完整路径
String command = "C:\\Program Files (x86)\\xnms-install\\mysql\\bin\\mysqldump.exe -h localhost -P 13306 -u root -p123456 --databases cvt_db";
方法2:使用 cmd /c 执行命令
// 让 cmd 解释器来执行命令
String command = "cmd /c \"C:\\Program Files (x86)\\xnms-install\\mysql\\bin\\mysqldump.exe -h localhost -P 13306 -u root -p123456 --databases cvt_db\"";
方法3:设置工作目录
// 使用 ProcessBuilder 设置工作目录
ProcessBuilder pb = new ProcessBuilder("mysqldump.exe", "-h", "localhost", "-P", "13306", "-u", "root", "-p123456", "--databases", "cvt_db"
);
pb.directory(new File("C:\\Program Files (x86)\\xnms-install\\mysql\\bin"));
Process process = pb.start();
错误场景3:备份命令是否带空格
假设命令不带空格,直接执行该命令没问题,可以生成sql文件
E:\WorkSpace2\mysql\bin\mysqldump.exe -h 10.110.24.62 -P 13306 -u root -p123456 --databases cvt_db>E:\WorkSpace2\xnms-app\mysqlBackup\cvt_db-20251009162355.sql
如果命令带空格或者(),比如mysqldump.exe存在的路径是
E:\Work Space (x2)\mysql\bin\mysqldump.exe
那么执行这个命令是错误的,会报错如下
'E:\Work' 不是内部或外部命令,也不是可运行的程序或批处理文件。
分析
:为什么会这样?
答案
:如果带空格在cmd进行解析时候,它不会把它当成命令执行,此实你就需要带双引号包裹,这时候你会想到的方案,或者网上找到的方案是加双引号,这个时候你的java生成的命令可能会长成这样
\"E:\WorkSpace2\mysql\bin\mysqldump.exe\" -h 10.110.24.62 -P 13306 -u root -p123456 --databases cvt_db>\"E:\WorkSpace2\xnms-app\mysqlBackup\cvt_db-20251009162355.sql\"
此实验证你会发现,这个命令放到cmd窗口执行是完全可以执行成功的,但是走如果你采用错误场景1的方法1会发现执行还是无法生成sql文件,所以解决方案应该是采用方案2的写法,不能使用方案1的写法。
错误场景4:‘C:\Program’ 不是内部或外部命令,也不是可运行的程序或批处理文件。
C:\Users\Administrator>C:\Program Files (x86)\xnms-install\mysql\bin\mysqldump.exe -h localhost -P 13306 -u root -p123456 --databases cvt_db>C:\Program Files (x86)\xnms-install\xnms-app\mysqlBackup\cvt_db-20251009151450.sql
'C:\Program' 不是内部或外部命令,也不是可运行的程序
或批处理文件。
原因
:由于有空格没用双引号括起来,这个跟错误场景3差不多。
错误场景5:mysqldump: Got error: 1049: Unknown database ‘files’ when selecting the database
C:\Program Files (x86)\xnms-install\mysql\bin>mysqldump.exe -h localhost -P 13306 -u root -p123456 --databases cvt_db > C:\Program Files (x86)\xnms-install\cvt-windows-service\..\xnms-app\mysqlBackup\test.sqlcvt_db-20251009101122.sql
mysqldump: [Warning] Using a password on the command line interface can be insecure.
mysqldump: Got error: 1049: Unknown database 'files' when selecting the database
问题分析
原因1
:因为命令中的重定向符号 > 后面的路径包含了空格,但没有用引号括起来,导致系统将路径解析错误。
系统将你的命令解析为:
- mysqldump.exe … --databases cvt_db - 这是正确的
- > - 重定向符号
- C:\Program - 被当作第一个参数
- Files - 被当作第二个参数(系统误认为这是数据库名)
所以 mysqldump 试图连接名为 “files” 的数据库,但该数据库不存在。
原因2
:路径中的 … 问题:Java 的 ProcessBuilder 或 Runtime.exec() 不能直接解析 … 相对路径
解决方案
方法1
:使用引号括起文件路径
mysqldump.exe -h localhost -P 13306 -u root -p123456 --databases cvt_db>"C:\Program Files (x86)\xnms-install\cvt-windows-service\..\xnms-app\mysqlBackup\test.sqlcvt_db-20251009101122.sql"
方法2
:简化路径(推荐)
mysqldump.exe -h localhost -P 13306 -u root -p123456 --databases cvt_db>"C:\xnms-install\xnms-app\mysqlBackup\test.sqlcvt_db-20251009101122.sql"
方法3
:先切换到目标目录再执行
cd "C:\Program Files (x86)\xnms-install\cvt-windows-service\..\xnms-app\mysqlBackup"
mysqldump.exe -h localhost -P 13306 -u root -p123456 --databases cvt_db>test.sqlcvt_db-20251009101122.sql
五、总结
错误场景原因有以下几种:
- 命令路径带空格,方案1写法不带空格不用加双引号,如果有空格请加双引号,所以采用方案2写法。
- 命令带…\这种返回上一级的有问题。
- 命令不要带cd \d的写法,Java编写解析有问题。
- 命令必须带-p123456,如果不带该参数,控制台会等待输入命令,但是程序执行期间如何输入命令?所以已经要带上不然无效果。