main
黄海 6 months ago
parent 37fba96fc5
commit f16d376674

@ -7,8 +7,6 @@ import com.jfinal.kit.PropKit;
import java.io.*;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class BackupMysqlUtil {
//数据库连接串
@ -22,15 +20,13 @@ public class BackupMysqlUtil {
* MySQL
*/
public String backup() {
PropKit.clear();
PropKit.use("application.properties");
jdbcUrl = PropKit.get("read.jdbcUrl");
user = PropKit.get("read.user");
password = PropKit.get("read.password");
// 获取配置
String host = getHostFromJdbcUrl(jdbcUrl);
String port = getPortFromJdbcUrl(jdbcUrl);
String database = getDatabaseFromJdbcUrl(jdbcUrl);
String host = CommonUtil.getHostFromJdbcUrl(jdbcUrl);
String port = CommonUtil.getPortFromJdbcUrl(jdbcUrl);
String database = CommonUtil.getDatabaseFromJdbcUrl(jdbcUrl);
// 生成备份文件名
String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
String backupFileName = timestamp + ".sql";
@ -40,7 +36,7 @@ public class BackupMysqlUtil {
try {
// 获取mysqldump路径
String mysqldumpPath = getMySQLDumpPath();
String mysqldumpPath = CommonUtil.getMySQLDumpPath();
// 构建命令(不包含密码)
ProcessBuilder pb = new ProcessBuilder(
mysqldumpPath,
@ -87,55 +83,6 @@ public class BackupMysqlUtil {
}
}
/**
* mysqldump
*/
private 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
*/
private String getHostFromJdbcUrl(String jdbcUrl) {
String[] parts = jdbcUrl.split("://")[1].split(":");
return parts[0];
}
/**
* JDBC URL
*/
private String getPortFromJdbcUrl(String jdbcUrl) {
String[] parts = jdbcUrl.split("://")[1].split(":");
return parts[1].split("/")[0];
}
/**
* JDBC URL
*/
private 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);
}
}
public String doAction() {
String sourceFile = backup();

@ -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…
Cancel
Save