当前位置: 首页 > news >正文

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

文章目录

  • 1.代码
  • 2.Main方法打包
  • 3.Jar包打成exe可执行文件
  • 4.使用
    • (1.)准备一个表结构一样得数据库
    • (2.)打开软件
    • (3.)输入路径
  • 5.恢复成功

本文档只是为了留档方便以后工作运维,或者给同事分享文档内容比较简陋命令也不是特别全,不适合小白观看,如有不懂可以私信,上班期间都是在得

前文连接=====》mysql8 使用idb文件实现数据备份

需求,昨天写个数据恢复呗同事嫌麻烦,让我写个脚本一键恢复,一开始想着存储过程,但是存储过程不能移动文件,索性写个可视化界面吧。
下面直接cv就行了

1.代码

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; // 显示文件夹路径的标签1private static JLabel folderPathLabel2; // 显示文件夹路径的标签2public 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 {@Overridepublic 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);}
}

2.Main方法打包

Main方法打包教程

3.Jar包打成exe可执行文件

使用launch4j把Jar包打成exe教程

4.使用

(1.)准备一个表结构一样得数据库

数据库

(2.)打开软件

软件

打开软件输入账号密码和要恢复得库

(3.)输入路径

在这里插入图片描述
在这里插入图片描述

点击恢复

5.恢复成功

在这里插入图片描述
在这里插入图片描述

待优化,理论上只需要输入备份得文件夹,但是领导催我干别的了,以后有机会在优化一下。

如果点赞多,评论多会更新详细教程,待补充。

相关文章:

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

文章目录 1.代码2.Main方法打包3.Jar包打成exe可执行文件4.使用(1.)准备一个表结构一样得数据库(2.)打开软件(3.)输入路径 5.恢复成功 本文档只是为了留档方便以后工作运维,或者给同事分享文档内…...

Spring Boot面试题

1.什么是SpringBoot?它的主要特点是什么? Spring Boot 是一个基于 Spring 框架的开发和构建应用程序的工具,它旨在简化 Spring 应用的初始搭建和开发过程。Spring Boot 提供了一种约定优于配置的方式,通过自动配置和默认值&#…...

原生页面引入Webpack打包JS

Webpack简介 概述: Webpack是一个现代JavaScript应用程序的静态模块打包器。它将应用程序中的每个文件视为一个模块,并通过配置规则来解析这些模块之间的依赖关系,最终将其打包成一个或多个浏览器可以执行的文件。动态加载(Code …...

健康之路押注医药零售:毛利率下滑亏损扩大,医疗咨询人次大幅减少

《港湾商业观察》黄懿 2024年9月13日,健康之路股份有限公司(下称“健康之路”)再次递表港交所,建银国际为独家保荐人。健康之路国内运营主体为健康之路(中国)信息技术有限公司和福建健康之路信息技术有限公…...

【人工智能-初级】第7章 聚类算法K-Means:理论讲解与代码示例

文章目录 一、K-Means聚类简介二、K-Means 聚类的工作原理2.1 初始化簇中心2.2 分配簇标签2.3 更新簇中心2.4 迭代重复2.5 K-Means 算法的目标三、K-Means 聚类的优缺点3.1 优点3.2 缺点四、K 值的选择五、Python 实现 K-Means 聚类5.1 导入必要的库5.2 生成数据集并进行可视化…...

HOT 100 技巧题(136/169/75/31/287)

136. 只出现一次的数字 技巧类型题目,通过异或运算实现 169. 多数元素 三种常见解法:1. 哈希2. 排序3. 投票法 75. 颜色分类 单指针 两次遍历:第一次遍历把所有0都交换到前面,记录最后一个0的位置index,第二次遍…...

什么是时间戳?怎么获取?有什么用?

在 JavaScript 中,时间戳通常表示为自 1970 年 1 月 1 日 00:00:00 UTC 以来的毫秒数。我们可以使用 Date 对象来获取当前时间的时间戳,或者将特定的日期转换为时间戳。在JavaScript中,时间戳通常以毫秒为单位表示。 如何获取时间戳 在Java…...

LeetCode:459重复的子字符串

给定一个非空的字符串 s ,检查是否可以通过由它的一个子串重复多次构成。 示例 1: 输入: s "abab" 输出: true 解释: 可由子串 "ab" 重复两次构成。示例 2: 输入: s "aba" 输出: false示例 3: 输入: s "abcabcabcabc" 输…...

【含开题报告+文档+PPT+源码】基于SSM的旅游与自然保护平台开发与实现

开题报告 围场县拥有丰富的自然景观和野生动植物资源,同时面临着旅游业发展和自然保护之间的平衡问题,通过强调自然保护,这个平台可以教育游客如何尊重和保护当地的生态环境。同时,平台还可以提供关于生态保护的信息,…...

【ANTs】医疗影像工具ANTs多种安装方式教程

介绍ANTs的几种简单的安装教程 基于Releases的安装 Github上选择适配自己操作系统的安装包,链接: link 一般使用最新版本。这里官方操作说明,支持Ubuntu、MacOS、CentOS,但是windows有安装包,不知道怎么用。。。 下载后有两个文件夹,bin和lib,bin里面长这样(图示wind…...

想要音频里的人声,怎么把音频里的人声和音乐分开?

在音频处理领域,将音频中的人声和音乐分开是一个常见需求,尤其对于音乐制作、影视后期以及个人娱乐应用来说,这种分离技术显得尤为重要。随着科技的发展,现在已经有多种方法可以实现这一目的。 一、使用专业音频处理软件 市面上有…...

python代码中通过pymobiledevice3访问iOS沙盒目录获取app日志

【背景】 在进行业务操作过程中,即在app上的一些操作,在日志中会有对应的节点,例如,下面是查看设备实时视频过程对应的一些关键节点: 1、TxDeviceAwakeLogicHelper:wakeStart deviceId CxD2BA11000xxxx …...

Spring AOP 使用方法总结

AOP切面编程的最佳应用场景 记录日志性能监控事务管理处理异常数据验证,验证传入参数的正确性(一般不用这个方法做,而是用拦截器) spring提供了以下注解供开发者使用,编写AOP程序 Aspect 申明切面Pointcut 切点&#…...

LeetCode 每日一题 2024/10/21-2024/10/27

记录了初步解题思路 以及本地实现代码;并不一定为最优 也希望大家能一起探讨 一起进步 目录 10/21 910. 最小差值 II10/22 3184. 构成整天的下标对数目 I10/23 3185. 构成整天的下标对数目 II10/24 3175. 找到连续赢 K 场比赛的第一位玩家10/25 3180. 执行操作可获得…...

不到1500元的I卡可以玩转3A大作吗?撼与科技Intel Arc A750显卡游戏性能实

一、前言 还记得2022年10月的时候,英特尔发布了Arc A750和A770显卡,和此前所发布的DG1、A380不同,这两张显卡可以说是真正意义上的游戏显卡。不知不觉间,两年已经过去了,在这两年期间,英特尔不仅在积极地打…...

STK与MATLAB互联——仿真导航卫星与地面用户间距离和仰角参数

文章目录 构建GPS星座创建单个PRN的GPS卫星创建GPS星座,并为其添加发射机 北斗星座构建搭建低轨铱星星座构建一颗轨道高度为800km/1000km/1200km的低轨卫星构建一颗轨道高度为800km/1000km/1200km的低轨卫星建立地面站,可见性分析确定地面站坐标分析单颗…...

js面试问题笔记(一)

一.热门js面试 1.简述同步和异步的区别? 同步: 浏览器访问服务器请求,用户看到页面刷新 ,重新发请求,等请求完,页面刷新,新内容出现,用户看到新内容,进行下一步操作 异步: 浏览器访问服务器请求,用户正常操作,浏览器后端进行请求,等请求完,页面不刷新,新内容也会出现,用户看到…...

pip 和 pipx 的主要区别?

特性pippipx用途用于安装Python库或命令行应用程序,可以安装带entry points的库专门用于安装和管理Python命令行工具,每个工具都在隔离的虚拟环境中运行虚拟环境不自动创建虚拟环境,需要手动使用 venv 或 virtualenv 创建自动为每个安装的工具…...

4457M数字示波器

_XLT新利通_ 4457M数字示波器 带宽500MHz到3GHz 4457M系列数字示波器产品,包含4457DM/EM/FM/GM四个产品型号,模拟通道数4、8个,带宽500MHz到3GHz,最高采样率10GSa/s,垂直分辨率8bit,最大存储深度2Gpts。…...

【永中软件-注册/登录安全分析报告】

前言 由于网站注册入口容易被黑客攻击,存在如下安全问题: 暴力破解密码,造成用户信息泄露短信盗刷的安全问题,影响业务及导致用户投诉带来经济损失,尤其是后付费客户,风险巨大,造成亏损无底洞…...

K8S认证|CKS题库+答案| 11. AppArmor

目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作: 1)、切换集群 2)、切换节点 3)、切换到 apparmor 的目录 4)、执行 apparmor 策略模块 5)、修改 pod 文件 6)、…...

【Oracle APEX开发小技巧12】

有如下需求: 有一个问题反馈页面,要实现在apex页面展示能直观看到反馈时间超过7天未处理的数据,方便管理员及时处理反馈。 我的方法:直接将逻辑写在SQL中,这样可以直接在页面展示 完整代码: SELECTSF.FE…...

【JavaEE】-- HTTP

1. HTTP是什么? HTTP(全称为"超文本传输协议")是一种应用非常广泛的应用层协议,HTTP是基于TCP协议的一种应用层协议。 应用层协议:是计算机网络协议栈中最高层的协议,它定义了运行在不同主机上…...

阿里云ACP云计算备考笔记 (5)——弹性伸缩

目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...

.Net框架,除了EF还有很多很多......

文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...

Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例

使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件,常用于在两个集合之间进行数据转移,如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model:绑定右侧列表的值&…...

循环冗余码校验CRC码 算法步骤+详细实例计算

通信过程:(白话解释) 我们将原始待发送的消息称为 M M M,依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)(意思就是 G ( x ) G(x) G(x) 是已知的)&#xff0…...

Python爬虫实战:研究feedparser库相关技术

1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的信息资源。RSS(Really Simple Syndication)作为一种标准化的信息聚合技术,被广泛用于网站内容的发布和订阅。通过 RSS,用户可以方便地获取网站更新的内容,而无需频繁访问各个网站。 然而,互联网…...

前端导出带有合并单元格的列表

// 导出async function exportExcel(fileName "共识调整.xlsx") {// 所有数据const exportData await getAllMainData();// 表头内容let fitstTitleList [];const secondTitleList [];allColumns.value.forEach(column > {if (!column.children) {fitstTitleL…...

Cloudflare 从 Nginx 到 Pingora:性能、效率与安全的全面升级

在互联网的快速发展中,高性能、高效率和高安全性的网络服务成为了各大互联网基础设施提供商的核心追求。Cloudflare 作为全球领先的互联网安全和基础设施公司,近期做出了一个重大技术决策:弃用长期使用的 Nginx,转而采用其内部开发…...