|
|
|
@ -1,183 +0,0 @@
|
|
|
|
|
package com.dsideal.YunXiaoTools.Service;
|
|
|
|
|
|
|
|
|
|
import java.io.*;
|
|
|
|
|
import java.sql.*;
|
|
|
|
|
import java.util.ArrayList;
|
|
|
|
|
import java.util.List;
|
|
|
|
|
|
|
|
|
|
public class DatabaseRestorer {
|
|
|
|
|
private final String jdbcUrl;
|
|
|
|
|
private final String username;
|
|
|
|
|
private final String password;
|
|
|
|
|
|
|
|
|
|
public DatabaseRestorer(String jdbcUrl, String username, String password) {
|
|
|
|
|
this.jdbcUrl = jdbcUrl;
|
|
|
|
|
this.username = username;
|
|
|
|
|
this.password = password;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 还原数据库
|
|
|
|
|
*/
|
|
|
|
|
public void restore(String sqlFile) {
|
|
|
|
|
try {
|
|
|
|
|
// 读取SQL文件内容
|
|
|
|
|
List<String> sqlStatements = parseSqlFile(sqlFile);
|
|
|
|
|
System.out.println("SQL文件解析完成,共 " + sqlStatements.size() + " 条语句");
|
|
|
|
|
|
|
|
|
|
// 执行SQL语句
|
|
|
|
|
try (Connection conn = DriverManager.getConnection(jdbcUrl, username, password)) {
|
|
|
|
|
conn.setAutoCommit(false); // 开启事务
|
|
|
|
|
|
|
|
|
|
try (Statement stmt = conn.createStatement()) {
|
|
|
|
|
int total = sqlStatements.size();
|
|
|
|
|
int current = 0;
|
|
|
|
|
|
|
|
|
|
for (String sql : sqlStatements) {
|
|
|
|
|
if (sql.trim().length() > 0) {
|
|
|
|
|
try {
|
|
|
|
|
stmt.execute(sql);
|
|
|
|
|
current++;
|
|
|
|
|
|
|
|
|
|
// 显示进度
|
|
|
|
|
if (current % 100 == 0 || current == total) {
|
|
|
|
|
System.out.printf("\r还原进度: %.2f%% (%d/%d)",
|
|
|
|
|
(current * 100.0 / total), current, total);
|
|
|
|
|
}
|
|
|
|
|
} catch (SQLException e) {
|
|
|
|
|
System.err.println("\n执行SQL出错: " + sql);
|
|
|
|
|
System.err.println("错误信息: " + e.getMessage());
|
|
|
|
|
throw e;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
conn.commit(); // 提交事务
|
|
|
|
|
System.out.println("\n数据库还原完成");
|
|
|
|
|
|
|
|
|
|
} catch (SQLException e) {
|
|
|
|
|
conn.rollback(); // 发生错误时回滚
|
|
|
|
|
throw e;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
throw new RuntimeException("还原数据库失败: " + e.getMessage(), e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 解析SQL文件
|
|
|
|
|
*/
|
|
|
|
|
private List<String> parseSqlFile(String sqlFile) throws IOException {
|
|
|
|
|
List<String> sqlStatements = new ArrayList<>();
|
|
|
|
|
StringBuilder statement = new StringBuilder();
|
|
|
|
|
boolean inString = false;
|
|
|
|
|
|
|
|
|
|
try (BufferedReader reader = new BufferedReader(new FileReader(sqlFile))) {
|
|
|
|
|
String line;
|
|
|
|
|
while ((line = reader.readLine()) != null) {
|
|
|
|
|
// 跳过注释行
|
|
|
|
|
if (line.trim().startsWith("--") || line.trim().startsWith("/*")) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < line.length(); i++) {
|
|
|
|
|
char c = line.charAt(i);
|
|
|
|
|
|
|
|
|
|
// 处理字符串
|
|
|
|
|
if (c == '\'') {
|
|
|
|
|
inString = !inString;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
statement.append(c);
|
|
|
|
|
|
|
|
|
|
// 如果遇到分号且不在字符串中,说明一条语句结束
|
|
|
|
|
if (c == ';' && !inString) {
|
|
|
|
|
sqlStatements.add(statement.toString());
|
|
|
|
|
statement = new StringBuilder();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
statement.append("\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 处理最后一条可能没有分号的语句
|
|
|
|
|
if (statement.length() > 0) {
|
|
|
|
|
sqlStatements.add(statement.toString());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return sqlStatements;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 还原数据库(带进度回调)
|
|
|
|
|
*/
|
|
|
|
|
public void restore(String sqlFile, ProgressCallback callback) {
|
|
|
|
|
try {
|
|
|
|
|
callback.onStart("正在解析SQL文件...");
|
|
|
|
|
List<String> sqlStatements = parseSqlFile(sqlFile);
|
|
|
|
|
|
|
|
|
|
callback.onProgress("开始执行SQL语句", 0);
|
|
|
|
|
try (Connection conn = DriverManager.getConnection(jdbcUrl, username, password)) {
|
|
|
|
|
conn.setAutoCommit(false);
|
|
|
|
|
|
|
|
|
|
try (Statement stmt = conn.createStatement()) {
|
|
|
|
|
int total = sqlStatements.size();
|
|
|
|
|
int current = 0;
|
|
|
|
|
long startTime = System.currentTimeMillis();
|
|
|
|
|
|
|
|
|
|
for (String sql : sqlStatements) {
|
|
|
|
|
if (sql.trim().length() > 0) {
|
|
|
|
|
try {
|
|
|
|
|
stmt.execute(sql);
|
|
|
|
|
current++;
|
|
|
|
|
|
|
|
|
|
// 计算进度和速度
|
|
|
|
|
if (current % 10 == 0 || current == total) {
|
|
|
|
|
int progress = (int) ((current * 100.0) / total);
|
|
|
|
|
long elapsed = System.currentTimeMillis() - startTime;
|
|
|
|
|
double speed = current * 1000.0 / elapsed;
|
|
|
|
|
|
|
|
|
|
callback.onProgress(
|
|
|
|
|
String.format("已执行 %d/%d 条语句 (%.2f条/秒)",
|
|
|
|
|
current, total, speed),
|
|
|
|
|
progress
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
} catch (SQLException e) {
|
|
|
|
|
callback.onError("执行SQL出错: " + sql, e);
|
|
|
|
|
throw e;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
conn.commit();
|
|
|
|
|
callback.onComplete("数据库还原完成");
|
|
|
|
|
|
|
|
|
|
} catch (SQLException e) {
|
|
|
|
|
conn.rollback();
|
|
|
|
|
throw e;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
callback.onError("还原失败", e);
|
|
|
|
|
throw new RuntimeException("还原数据库失败: " + e.getMessage(), e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 进度回调接口
|
|
|
|
|
*/
|
|
|
|
|
public interface ProgressCallback {
|
|
|
|
|
void onStart(String message);
|
|
|
|
|
|
|
|
|
|
void onProgress(String message, int percent);
|
|
|
|
|
|
|
|
|
|
void onError(String message, Exception e);
|
|
|
|
|
|
|
|
|
|
void onComplete(String message);
|
|
|
|
|
}
|
|
|
|
|
}
|