MySQL根据.idb数据恢复脚本,做成了EXE可执行文件

时间:2024-10-27 20:01:18
package com.joxp.mysql; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; import java.io.IOException; import java.nio.file.*; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; public class MySQLConnectionApp { private static JFrame frame; // 主窗口 private static JTextField userField; // 用户名输入框 private static JPasswordField passwordField; // 密码输入框 private static JTextField dbNameField; // 数据库名称输入框 private static String selectedFolder1; // 第一个选择的文件夹路径 private static String selectedFolder2; // 第二个选择的文件夹路径 private static JLabel folderPathLabel1; // 显示文件夹路径的标签1 private static JLabel folderPathLabel2; // 显示文件夹路径的标签2 public static void main(String[] args) { SwingUtilities.invokeLater(MySQLConnectionApp::createAndShowGUI); } private static void createAndShowGUI() { frame = new JFrame("MySQL 连接器"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(400, 300); frame.setLayout(new GridLayout(5, 2)); JLabel userLabel = new JLabel("用户名:"); userField = new JTextField(); JLabel passwordLabel = new JLabel("密码:"); passwordField = new JPasswordField(); JLabel dbNameLabel = new JLabel("数据库名:"); dbNameField = new JTextField(); // 创建右下角的标签 JLabel footerLabel = new JLabel("By:XHao"); footerLabel.setHorizontalAlignment(SwingConstants.LEFT); // 左对齐 JButton connectButton = new JButton("连接"); connectButton.addActionListener(new ConnectAction()); JLabel messageLabel = new JLabel("", SwingConstants.CENTER); frame.add(userLabel); frame.add(userField); frame.add(passwordLabel); frame.add(passwordField); frame.add(dbNameLabel); frame.add(dbNameField); frame.add(connectButton); frame.add(messageLabel); frame.add(footerLabel); // 添加 footerLabel 到最后 frame.setVisible(true); } private static void updateUIAfterConnection() { frame.getContentPane().removeAll(); frame.setLayout(new GridLayout(5, 1)); // 新布局为5行1列 frame.setSize(700, 350); // 根据需要调整宽度和高度 JButton selectFolderButton1 = new JButton("选择备份文件夹"); JButton selectFolderButton2 = new JButton("选择恢复文件夹"); JButton queryButton = new JButton("查询数据路径"); JButton recoverButton = new JButton("恢复数据"); JLabel queryResultLabel = new JLabel(""); // 用于显示查询结果 // 固定按钮大小 Dimension buttonSize = new Dimension(80, 30); selectFolderButton1.setPreferredSize(buttonSize); selectFolderButton2.setPreferredSize(buttonSize); queryButton.setPreferredSize(buttonSize); recoverButton.setPreferredSize(buttonSize); folderPathLabel1 = new JLabel("未选择文件夹"); folderPathLabel1.setSize(80, 30); folderPathLabel2 = new JLabel("未选择文件夹"); folderPathLabel2.setSize(80, 30); selectFolderButton1.addActionListener(e -> { selectedFolder1 = openFolderChooser(); folderPathLabel1.setText(selectedFolder1 != null ? selectedFolder1 : "未选择文件夹"); }); // 创建右下角的标签 JLabel footerLabel = new JLabel("By:XHao"); JLabel aaa = new JLabel(""); footerLabel.setHorizontalAlignment(SwingConstants.LEFT); // 左对齐 aaa.setHorizontalAlignment(SwingConstants.LEFT); // 左对齐 selectFolderButton2.addActionListener(e -> { selectedFolder2 = openFolderChooser(); folderPathLabel2.setText(selectedFolder2 != null ? selectedFolder2 : "未选择文件夹"); }); queryButton.addActionListener(e -> { String result = executeQuery(); // 假设 executeQuery() 返回查询结果 queryResultLabel.setText(result); // 显示在下方标签 }); recoverButton.addActionListener(e -> executeRecovery()); // 将按钮和标签添加到框架中 frame.add(selectFolderButton1); frame.add(folderPathLabel1); frame.add(selectFolderButton2); frame.add(folderPathLabel2); frame.add(queryButton); frame.add(recoverButton); frame.add(queryResultLabel); frame.add(aaa, BorderLayout.SOUTH); frame.add(footerLabel, BorderLayout.SOUTH); // 将footerLabel放在底部 frame.revalidate(); frame.repaint(); } private static String openFolderChooser() { JFileChooser folderChooser = new JFileChooser(); folderChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); int returnValue = folderChooser.showOpenDialog(frame); if (returnValue == JFileChooser.APPROVE_OPTION) { File selectedFolder = folderChooser.getSelectedFile(); return selectedFolder.getAbsolutePath(); } return null; } private static String executeQuery() { String query = "SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(@@datadir, '/', -1), '/', 1) as aa;"; try (Connection conn = getConnection(); Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery(query)) { StringBuilder result = new StringBuilder(); while (rs.next()) { result.append(rs.getString("aa")).append("\n"); } if (result.length() == 0) { result.append("没有找到任何结果。"); } return result.toString(); } catch (SQLException e) { showErrorDialog("查询失败: " + e.getMessage()); } return null; } private static void executeRecovery() { // 第一步,执行第一个存储过程 try (Connection conn = getConnection(); Statement stmt = conn.createStatement()) { String dropProcedureSQL = "DROP PROCEDURE IF EXISTS " + "your_first_stored_procedure" + ";"; stmt.execute(dropProcedureSQL); // 创建存储过程 String abc = "CREATE DEFINER=`root`@`%` PROCEDURE `your_first_stored_procedure`(IN dbName VARCHAR(255))\n" + "BEGIN\n" + " DECLARE done INT DEFAULT FALSE;\n" + " DECLARE tableName VARCHAR(255);\n" + "\n" + " -- 定义游标\n" + " DECLARE cur CURSOR FOR \n" + " SELECT TABLE_NAME \n" + " FROM information_schema.TABLES \n" + " WHERE TABLE_SCHEMA = dbName;\n" + "\n" + " -- 错误处理\n" + " DECLARE CONTINUE HANDLER FOR SQLEXCEPTION\n" + " BEGIN\n" + " -- 错误发生时不做任何处理,继续执行\n" + " END;\n" + "\n" + " DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;\n" + "\n" + " -- 第一个循环:遍历所有表并执行 DISCARD TABLESPACE\n" + " OPEN cur;\n" + "\n" + " read_loop_1: LOOP\n" + " FETCH cur INTO tableName;\n" + " IF done THEN\n" + " LEAVE read_loop_1;\n" + " END IF;\n" + "\n" + " -- 执行 DISCARD TABLESPACE\n" + " SET @discard_sql = CONCAT('ALTER TABLE ', dbName, '.', tableName, ' DISCARD TABLESPACE;');\n" + " PREPARE stmt FROM @discard_sql;\n" + " EXECUTE stmt;\n" + " DEALLOCATE PREPARE stmt;\n" + "\n" + " -- 在此处可以执行其他操作\n" + " -- 例如:INSERT INTO logging_table (message) VALUES (CONCAT('Discarded tablespace for ', tableName));\n" + " END LOOP;\n" + "\n" + " -- 关闭游标\n" + " CLOSE cur;\n" + "END;"; // 执行创建存储过程 stmt.execute(abc); stmt.execute("CALL your_first_stored_procedure('" + dbNameField.getText() + "')"); stmt.execute(dropProcedureSQL); // 第二步,复制文件 if (selectedFolder1 != null && selectedFolder2 != null) { copyFiles(selectedFolder1, selectedFolder2); } else { showErrorDialog("请确保选择了两个文件夹。"); return; } String aaaa = "DROP PROCEDURE IF EXISTS " + "your_second_stored_procedure" + ";"; stmt.execute(aaaa); // 创建存储过程 String aa = " CREATE DEFINER=`root`@`%` PROCEDURE `your_second_stored_procedure`(IN dbName VARCHAR(255))\n" + "BEGIN\n" + " DECLARE done INT DEFAULT FALSE;\n" + " DECLARE tableName VARCHAR(255);\n" + "\n" + " -- 定义游标\n" + " DECLARE cur CURSOR FOR \n" + " SELECT TABLE_NAME \n" + " FROM information_schema.TABLES \n" + " WHERE TABLE_SCHEMA = dbName;\n" + "\n" + " -- 错误处理\n" + " DECLARE CONTINUE HANDLER FOR SQLEXCEPTION\n" + " BEGIN\n" + " -- 错误发生时不做任何处理,继续执行\n" + " END;\n" + "\n" + " DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;\n" + "\n" + " -- 重新打开游标\n" + " OPEN cur;\n" + "\n" + " read_loop_2: LOOP\n" + " FETCH cur INTO tableName;\n" + " IF done THEN\n" + " LEAVE read_loop_2;\n" + " END IF;\n" + "\n" + " -- 执行 IMPORT TABLESPACE\n" + " SET @import_sql = CONCAT('ALTER TABLE ', dbName, '.', tableName, ' IMPORT TABLESPACE;');\n" + " PREPARE stmt FROM @import_sql;\n" + " EXECUTE stmt;\n" + " DEALLOCATE PREPARE stmt;\n" + "\n" + " -- 在此处可以执行其他操作\n" + " -- 例如:INSERT INTO logging_table (message) VALUES (CONCAT('Imported tablespace for ', tableName));\n" + " END LOOP;\n" + "\n" + " -- 关闭游标\n" + " CLOSE cur;\n" + "END;\n"; stmt.execute(aa); // 第三步,执行第二个存储过程 stmt.execute("CALL your_second_stored_procedure('" + dbNameField.getText() + "')"); // 替换为你的存储过程名 stmt.execute(aaaa); JOptionPane.showMessageDialog(frame, "恢复数据成功。", "成功", JOptionPane.INFORMATION_MESSAGE); } catch (SQLException e) { showErrorDialog("执行存储过程失败: " + e.getMessage()); } catch (IOException e) { showErrorDialog("文件复制失败: " + e.getMessage()); } } private static void copyFiles(String sourceFolder, String destFolder) throws IOException { Path sourcePath = Paths.get(sourceFolder); Path destPath = Paths.get(destFolder); Files.walk(sourcePath).forEach(source -> { Path dest = destPath.resolve(sourcePath.relativize(source)); try { if (Files.isDirectory(source)) { Files.createDirectories(dest); } else { Files.copy(source, dest, StandardCopyOption.REPLACE_EXISTING); } } catch (IOException e) { e.printStackTrace(); } }); } private static Connection getConnection() throws SQLException { String username = userField.getText(); String password = new String(passwordField.getPassword()); String dbName = dbNameField.getText(); String url = "jdbc:mysql://localhost:3306/" + dbName; return DriverManager.getConnection(url, username, password); } private static class ConnectAction implements ActionListener { @Override public void actionPerformed(ActionEvent e) { try { Class.forName("com.mysql.cj.jdbc.Driver"); getConnection(); updateUIAfterConnection(); } catch (ClassNotFoundException ex) { showErrorDialog("驱动未找到: " + ex.getMessage()); } catch (SQLException ex) { showErrorDialog("连接失败: " + ex.getMessage()); } } } private static void showErrorDialog(String message) { JOptionPane.showMessageDialog(frame, message, "连接错误", JOptionPane.ERROR_MESSAGE