parent
37fba96fc5
commit
f16d376674
@ -0,0 +1,59 @@
|
||||
package com.dsideal.YunXiaoTools.Utils;
|
||||
|
||||
import com.jfinal.kit.PropKit;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class CommonUtil {
|
||||
|
||||
/**
|
||||
* 获取mysqldump路径
|
||||
*/
|
||||
public static String getMySQLDumpPath() {
|
||||
try {
|
||||
String resourcePath = PropKit.get("mysqldump_path");
|
||||
// 处理路径中的空格和特殊字符
|
||||
if (resourcePath.startsWith("/")) {
|
||||
resourcePath = resourcePath.substring(1);
|
||||
}
|
||||
// URL解码
|
||||
return java.net.URLDecoder.decode(resourcePath, "UTF-8");
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("获取mysqldump路径失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从JDBC URL中提取主机地址
|
||||
*/
|
||||
public static String getHostFromJdbcUrl(String jdbcUrl) {
|
||||
String[] parts = jdbcUrl.split("://")[1].split(":");
|
||||
return parts[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* 从JDBC URL中提取端口号
|
||||
*/
|
||||
public static String getPortFromJdbcUrl(String jdbcUrl) {
|
||||
String[] parts = jdbcUrl.split("://")[1].split(":");
|
||||
return parts[1].split("/")[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* 从JDBC URL中提取数据库名
|
||||
*/
|
||||
public static String getDatabaseFromJdbcUrl(String jdbcUrl) {
|
||||
try {
|
||||
// 使用正则表达式匹配数据库名
|
||||
Pattern pattern = Pattern.compile("jdbc:mysql://[^/]+/(\\w+)\\??.*");
|
||||
Matcher matcher = pattern.matcher(jdbcUrl);
|
||||
if (matcher.find()) {
|
||||
return matcher.group(1);
|
||||
}
|
||||
throw new RuntimeException("无法从JDBC URL中提取数据库名: " + jdbcUrl);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("解析数据库名失败: " + jdbcUrl, e);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,185 @@
|
||||
package com.dsideal.YunXiaoTools.Utils;
|
||||
|
||||
import com.jfinal.kit.PropKit;
|
||||
import com.obs.services.ObsClient;
|
||||
import java.io.*;
|
||||
import java.util.zip.*;
|
||||
|
||||
public class DatabaseRestore {
|
||||
private final String obsEndpoint;
|
||||
private final String obsAccessKey;
|
||||
private final String obsSecretKey;
|
||||
private final String obsBucket;
|
||||
|
||||
// 目标数据库配置
|
||||
private final String dbHost;
|
||||
private final String dbPort;
|
||||
private final String dbUser;
|
||||
private final String dbPassword;
|
||||
private final String dbName;
|
||||
|
||||
public DatabaseRestore() {
|
||||
// 从配置文件读取配置
|
||||
this.obsEndpoint = PropKit.get("obs.endPoint");
|
||||
this.obsAccessKey = PropKit.get("obs.accessKey");
|
||||
this.obsSecretKey = PropKit.get("obs.secretKey");
|
||||
this.obsBucket = PropKit.get("obs.bucketName");
|
||||
|
||||
// 目标数据库配置
|
||||
this.dbHost = CommonUtil.getHostFromJdbcUrl(PropKit.get("write.jdbcUrl"));
|
||||
this.dbPort = CommonUtil.getPortFromJdbcUrl(PropKit.get("write.jdbcUrl"));
|
||||
this.dbUser = PropKit.get("write.user");
|
||||
this.dbPassword = PropKit.get("write.password");
|
||||
this.dbName = CommonUtil.getDatabaseFromJdbcUrl(PropKit.get("write.jdbcUrl"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行完整的还原流程
|
||||
* @param obsKey OBS上的文件路径
|
||||
*/
|
||||
public void restore(String obsKey) {
|
||||
String tempDir = System.getProperty("java.io.tmpdir");
|
||||
String zipFile = tempDir + File.separator + new File(obsKey).getName();
|
||||
String sqlFile = null;
|
||||
|
||||
try {
|
||||
// 1. 从OBS下载ZIP文件
|
||||
downloadFromObs(obsKey, zipFile);
|
||||
System.out.println("文件下载完成: " + zipFile);
|
||||
|
||||
// 2. 解压ZIP文件
|
||||
sqlFile = unzipFile(zipFile);
|
||||
System.out.println("文件解压完成: " + sqlFile);
|
||||
|
||||
// 3. 还原数据库
|
||||
restoreDatabase(sqlFile);
|
||||
System.out.println("数据库还原完成");
|
||||
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("还原过程失败: " + e.getMessage(), e);
|
||||
} finally {
|
||||
// 清理临时文件
|
||||
if (zipFile != null) {
|
||||
new File(zipFile).delete();
|
||||
}
|
||||
if (sqlFile != null) {
|
||||
new File(sqlFile).delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从OBS下载文件
|
||||
*/
|
||||
private void downloadFromObs(String obsKey, String localFile) {
|
||||
try (ObsClient obsClient = new ObsClient(obsAccessKey, obsSecretKey, obsEndpoint)) {
|
||||
obsClient.getObject(obsBucket, obsKey, String.valueOf(new File(localFile)));
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("从OBS下载文件失败: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解压ZIP文件
|
||||
*/
|
||||
private String unzipFile(String zipFile) throws IOException {
|
||||
String extractedFile = null;
|
||||
|
||||
try (ZipInputStream zis = new ZipInputStream(new FileInputStream(zipFile))) {
|
||||
ZipEntry zipEntry = zis.getNextEntry();
|
||||
if (zipEntry != null) {
|
||||
extractedFile = new File(zipFile).getParent() + File.separator + zipEntry.getName();
|
||||
|
||||
try (BufferedOutputStream bos = new BufferedOutputStream(
|
||||
new FileOutputStream(extractedFile))) {
|
||||
byte[] buffer = new byte[8192];
|
||||
int len;
|
||||
while ((len = zis.read(buffer)) > 0) {
|
||||
bos.write(buffer, 0, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (extractedFile == null) {
|
||||
throw new RuntimeException("ZIP文件中没有找到SQL文件");
|
||||
}
|
||||
|
||||
return extractedFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* 还原数据库
|
||||
*/
|
||||
private void restoreDatabase(String sqlFile) {
|
||||
try {
|
||||
// 获取mysql命令路径
|
||||
String mysqlPath = getMySQLPath();
|
||||
|
||||
// 构建还原命令
|
||||
ProcessBuilder pb = new ProcessBuilder(
|
||||
mysqlPath,
|
||||
"-h" + dbHost,
|
||||
"-P" + dbPort,
|
||||
"-u" + dbUser,
|
||||
"--ssl-mode=DISABLED",
|
||||
dbName
|
||||
);
|
||||
|
||||
// 设置环境变量传递密码
|
||||
pb.environment().put("MYSQL_PWD", dbPassword);
|
||||
|
||||
// 执行还原命令
|
||||
Process process = pb.start();
|
||||
|
||||
// 将SQL文件内容写入mysql进程的输入流
|
||||
try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(sqlFile));
|
||||
BufferedOutputStream bos = new BufferedOutputStream(process.getOutputStream())) {
|
||||
|
||||
byte[] buffer = new byte[8192];
|
||||
int len;
|
||||
while ((len = bis.read(buffer)) > 0) {
|
||||
bos.write(buffer, 0, len);
|
||||
}
|
||||
}
|
||||
|
||||
// 读取错误输出
|
||||
StringBuilder errorOutput = new StringBuilder();
|
||||
try (BufferedReader reader = new BufferedReader(
|
||||
new InputStreamReader(process.getErrorStream()))) {
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
if (!line.contains("WARNING")) {
|
||||
errorOutput.append(line).append("\n");
|
||||
System.out.println("还原进度: " + line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 等待命令执行完成
|
||||
int exitCode = process.waitFor();
|
||||
if (exitCode != 0) {
|
||||
throw new RuntimeException("数据库还原失败:\n" + errorOutput.toString());
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("还原数据库失败: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取mysql命令路径
|
||||
*/
|
||||
private String getMySQLPath() {
|
||||
try {
|
||||
String resourcePath = getClass().getClassLoader()
|
||||
.getResource("mysql.exe").getPath();
|
||||
if (resourcePath.startsWith("/")) {
|
||||
resourcePath = resourcePath.substring(1);
|
||||
}
|
||||
return java.net.URLDecoder.decode(resourcePath, "UTF-8");
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("获取mysql路径失败", e);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in new issue