From 8df0f1bacaa99229d47f478db5802a1868560e3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B5=B7?= <10402852@qq.com> Date: Fri, 10 Jan 2025 14:41:54 +0800 Subject: [PATCH] 'commit' --- .../Service/DatabaseRestorer.java | 183 ++++++++++++++++++ .../Service/MysqlBackupService.java | 24 ++- .../Service/MysqlRestoreService.java | 102 +--------- .../src/main/resources/application.properties | 4 +- .../target/classes/application.properties | 4 +- 5 files changed, 203 insertions(+), 114 deletions(-) create mode 100644 YunXiaoTools/src/main/java/com/dsideal/YunXiaoTools/Service/DatabaseRestorer.java diff --git a/YunXiaoTools/src/main/java/com/dsideal/YunXiaoTools/Service/DatabaseRestorer.java b/YunXiaoTools/src/main/java/com/dsideal/YunXiaoTools/Service/DatabaseRestorer.java new file mode 100644 index 00000000..43791e1a --- /dev/null +++ b/YunXiaoTools/src/main/java/com/dsideal/YunXiaoTools/Service/DatabaseRestorer.java @@ -0,0 +1,183 @@ +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 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 parseSqlFile(String sqlFile) throws IOException { + List 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 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); + } +} \ No newline at end of file diff --git a/YunXiaoTools/src/main/java/com/dsideal/YunXiaoTools/Service/MysqlBackupService.java b/YunXiaoTools/src/main/java/com/dsideal/YunXiaoTools/Service/MysqlBackupService.java index df4f5236..f91fe434 100644 --- a/YunXiaoTools/src/main/java/com/dsideal/YunXiaoTools/Service/MysqlBackupService.java +++ b/YunXiaoTools/src/main/java/com/dsideal/YunXiaoTools/Service/MysqlBackupService.java @@ -40,22 +40,26 @@ public class MysqlBackupService { // 获取mysqldump路径 String mysqldumpPath = CommonUtil.getMySQLDumpPath(); // 构建命令(不包含密码) + + // MariaDB 兼容的备份命令 ProcessBuilder pb = new ProcessBuilder( mysqldumpPath, "-h" + host, "-P" + port, "-u" + user, - //"--ssl-mode=DISABLED", - "--skip-ssl", // MariaDB 使用 --skip-ssl - "--no-tablespaces", // 避免权限问题 + "--skip-ssl", + "--no-tablespaces", "--default-character-set=utf8", - "--single-transaction", - "--routines", - "--triggers", - "--events", - "--complete-insert", - "--add-drop-database", - "--add-drop-table", + "--single-transaction", // 保证数据一致性 + "--routines", // 包含存储过程 + "--triggers", // 包含触发器 + "--events", // 包含事件 + "--complete-insert", // 完整insert语句 + "--add-drop-database", // 添加drop database语句 + "--add-drop-table", // 添加drop table语句 + "--skip-lock-tables", // 跳过锁表 + "--compact", // 产生更紧凑的输出 + "--skip-extended-insert", // 分行显示insert语句 database, "-r", backupPath diff --git a/YunXiaoTools/src/main/java/com/dsideal/YunXiaoTools/Service/MysqlRestoreService.java b/YunXiaoTools/src/main/java/com/dsideal/YunXiaoTools/Service/MysqlRestoreService.java index 046373dd..9982134b 100644 --- a/YunXiaoTools/src/main/java/com/dsideal/YunXiaoTools/Service/MysqlRestoreService.java +++ b/YunXiaoTools/src/main/java/com/dsideal/YunXiaoTools/Service/MysqlRestoreService.java @@ -3,33 +3,12 @@ package com.dsideal.YunXiaoTools.Service; import com.dsideal.YunXiaoTools.Utils.CommonUtil; import com.dsideal.YunXiaoTools.Utils.MultiThreadDownloader; import com.jfinal.kit.PropKit; -import com.obs.services.ObsClient; import java.io.*; -import java.util.UUID; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; import java.util.zip.*; public class MysqlRestoreService { - // 目标数据库配置 - private final String dbHost; - private final String dbPort; - private final String dbUser; - private final String dbPassword; - private final String dbName; - - public MysqlRestoreService() { - // 目标数据库配置 - String jdbcUrl = PropKit.get("write.jdbcUrl"); - this.dbHost = CommonUtil.getHostFromJdbcUrl(jdbcUrl); - this.dbPort = CommonUtil.getPortFromJdbcUrl(jdbcUrl); - this.dbUser = PropKit.get("write.user"); - this.dbPassword = PropKit.get("write.password"); - this.dbName = CommonUtil.getDatabaseFromJdbcUrl(jdbcUrl); - } /** * 执行完整的还原流程 @@ -51,7 +30,8 @@ public class MysqlRestoreService { System.out.println("文件解压完成: " + sqlFile); // 3. 还原数据库 - restoreDatabase(sqlFile); + DatabaseRestorer dr=new DatabaseRestorer(PropKit.get("write.jdbcUrl"), PropKit.get("write.user"), PropKit.get("write.password")); + dr.restore(sqlFile); System.out.println("数据库还原完成"); } catch (Exception e) { @@ -119,84 +99,6 @@ public class MysqlRestoreService { return extractedFile; } - private void restoreDatabase(String sqlFile) { - try { - String mysqlPath = CommonUtil.getMySQLPath(); - ProcessBuilder pb = new ProcessBuilder( - mysqlPath, - "-h" + dbHost, - "-P" + dbPort, - "-u" + dbUser, - "--skip-ssl", - dbName - ); - pb.environment().put("MYSQL_PWD", dbPassword); - // 启动进程 - Process process = pb.start(); - // 使用多线程处理输入输出流,避免死锁 - ExecutorService executor = Executors.newFixedThreadPool(2); - // 处理错误输出流 - Future errorFuture = executor.submit(() -> { - try (BufferedReader reader = new BufferedReader( - new InputStreamReader(process.getErrorStream()))) { - String line; - while ((line = reader.readLine()) != null) { - if (!line.contains("WARNING")) { - System.out.println("还原进度: " + line); - } - } - } catch (IOException e) { - e.printStackTrace(); - } - }); - - // 处理输入流(SQL文件) - Future inputFuture = executor.submit(() -> { - try (BufferedInputStream sqlInput = new BufferedInputStream(new FileInputStream(sqlFile)); - BufferedOutputStream processOutput = new BufferedOutputStream(process.getOutputStream())) { - - byte[] buffer = new byte[8192]; - int len; - long total = 0; - long fileSize = new File(sqlFile).length(); - - while ((len = sqlInput.read(buffer)) != -1) { - processOutput.write(buffer, 0, len); - total += len; - - // 显示进度 - int progress = (int) ((total * 100) / fileSize); - System.out.printf("\r导入进度: %d%%", progress); - } - - // 重要:刷新并关闭输出流 - processOutput.flush(); - processOutput.close(); - } catch (IOException e) { - e.printStackTrace(); - } - }); - - // 等待输入输出处理完成 - try { - inputFuture.get(); - errorFuture.get(); - } catch (Exception e) { - throw new RuntimeException("处理输入输出流失败", e); - } finally { - executor.shutdown(); - } - - // 等待进程完成 - int exitCode = process.waitFor(); - if (exitCode != 0) { - throw new RuntimeException("数据库还原失败,退出码: " + exitCode); - } - System.out.println("\n数据库还原完成"); - } catch (Exception e) { - throw new RuntimeException("还原数据库失败: " + e.getMessage(), e); - } - } public static void main(String[] args) { PropKit.use("application.properties"); diff --git a/YunXiaoTools/src/main/resources/application.properties b/YunXiaoTools/src/main/resources/application.properties index 82ab339f..c8b00b86 100644 --- a/YunXiaoTools/src/main/resources/application.properties +++ b/YunXiaoTools/src/main/resources/application.properties @@ -12,9 +12,9 @@ write.password=Password123@mysql write.jdbcUrl=jdbc:mysql://10.10.14.203:3306/HuangHai_Test?rewriteBatchedStatements=true&useUnicode=true&zeroDateTimeBehavior=CONVERT_TO_NULL&useSSL=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&autoReconnect=true&failOverReadOnly=false # mysqldump执行文件位置 -mysqldump_path=D:/ffmpeg/mysqldump.exe +mysqldump_path=C:/Program Files/MariaDB 11.6/bin/mysqldump.exe # mysql执行文件位置 -mysql_path=D:/ffmpeg/mysql.exe +mysql_path=C:/Program Files/MariaDB 11.6/bin/mysql.exe # 当前是读取方还是写入方 1:读取 2:写入 DEPLOY_ID=1 diff --git a/YunXiaoTools/target/classes/application.properties b/YunXiaoTools/target/classes/application.properties index 82ab339f..c8b00b86 100644 --- a/YunXiaoTools/target/classes/application.properties +++ b/YunXiaoTools/target/classes/application.properties @@ -12,9 +12,9 @@ write.password=Password123@mysql write.jdbcUrl=jdbc:mysql://10.10.14.203:3306/HuangHai_Test?rewriteBatchedStatements=true&useUnicode=true&zeroDateTimeBehavior=CONVERT_TO_NULL&useSSL=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&autoReconnect=true&failOverReadOnly=false # mysqldump执行文件位置 -mysqldump_path=D:/ffmpeg/mysqldump.exe +mysqldump_path=C:/Program Files/MariaDB 11.6/bin/mysqldump.exe # mysql执行文件位置 -mysql_path=D:/ffmpeg/mysql.exe +mysql_path=C:/Program Files/MariaDB 11.6/bin/mysql.exe # 当前是读取方还是写入方 1:读取 2:写入 DEPLOY_ID=1