MYSQL80 通过ibd文件 恢复表结构

        生产环境mysql数据库爆炸(windows),无法启动mysql。幸好ibd数据还在,所以查阅各种帖子,自己整理了一套恢复完整数据的方法。思路以及技术都比较简单,如有专业人士有更好的解决办法,欢迎沟通交流。

1,进入mysql 》data文件夹内,找到要恢复的库,将ibd文件备份出来。

2,在备份出来的文件夹内打开cmd,运行如下命令:

for /R %x in (*.ibd) do ibd2sdi --dump-file "%x".txt "%x"

       这是批量运行mysql自带的命令> ibd2sdi。如果cmd无法执行命令,可以添加mysql/bin目录为环境变量。

        这是批量转换后的txt文件。

        如图所示,这是txt的json内容。第2,第3个Object是数据表的相关数据。

        从这里面可以看到表名,字段,字段属性等等。图不完整,各位尝试后可仔细观察,所有信息都在此json 中。

3,有了json,用代码生成建表sql语句,代码如下:

  public void test() {
        Path tp = Paths.get("C:\\Users\\kings\\Desktop\\sxh-bak");
        try {
            List<Path> ps =    Files.walk(tp).map(Path::toAbsolutePath).collect(Collectors.toList());
            for (Path p : ps) {
                if (!Files.isDirectory(p)) {
                    String jsonStr = TxtUtil.readTxt(p.toString());
                    JSONArray ja = JSON.parseArray(jsonStr);
                    JSONObject table = ja.getJSONObject(1)
                            .getJSONObject("object")
                            .getJSONObject("dd_object");

                    String tableName = table.getString("name");
                    String comment = table.getString("comment");
                    JSONArray columns = table.getJSONArray("columns");

                    String start = "CREATE TABLE `" + tableName + "` ( \n";

                    LinkedList<String> cols = new LinkedList<>();

                    for (int i = 0; i < columns.size(); i++) {
                        JSONObject col = columns.getJSONObject(i);
                        String colName = col.getString("name");
                        String colType = col.getString("column_type_utf8");
                        boolean isNullable = col.getBoolean("is_nullable");
                        String nullableStr = isNullable ? "DEFAULT NULL" : "NOT NULL";
                        String colComment = col.getString("comment");
                        String colstr;
                        if (colName.equals("id")) {
                            colstr = " `id` bigint NOT NULL AUTO_INCREMENT,";
                        } else if (colName.equals("DB_TRX_ID") || colName.equals("DB_ROLL_PTR")) {
                            continue;
                        } else {
                            colstr = "`" + colName + "` " + colType + "  " + nullableStr + " COMMENT '" + colComment + "',";

                        }
                        cols.add(colstr);
                    }

                    String res = String.join("\n", cols);


                    String end = " PRIMARY KEY (`id`) \n" +
                            ") ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4;";

                    String finalres = start + res + end;
                    System.out.println(finalres);
                    TxtUtil.createAndWrite(finalres, p.getParent() +"\\" + tableName + ".sql");
                }



            }


        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }

4,代码相关

        上述代码中,比如主键,是否自增,索引什么的都没有仔细处理,各位自行斟酌。

5,恢复表数据

        5.1,删除表空间

        只要存在这个表,操作是肯定成功的。

ALTER TABLE `table_name` DISCARD TABLESPACE;

        5.2,复制ibd到Mysql 的 data 文件夹

         5.3,导入表空间

         如果当前表(恢复出来的)的表结构和ibd文件(原始的)的表结构不一样。操作会失败。在工具里打开这张表mysql 会停止服务。必须手动删除DATA文件夹内的ibd文件,再重启mysql服务。

ALTER TABLE `table_name` IMPORT TABLESPACE;

        该语句如正常执行,恭喜数据已完整恢复。

6,写在最后

        mysql5.x的data文件不太一样。本帖子应该不适用。

        数据无价,还是建议各位多备份。数据库出一次问题可是遭罪的很。

        ibd2sdi 相关参考链接:

【MySQL】ibd2sdi工具介绍和使用_SQLplusDB的博客-优快云博客

有些老哥需要工具类,这里补充下txtutil

@Slf4j
public class TxtUtil {


    public static String readTxt(String txtpath) {
        StringBuilder result = new StringBuilder();
        try {
            InputStreamReader isr = new InputStreamReader(Files.newInputStream(Paths.get(txtpath)), StandardCharsets.UTF_8);
            BufferedReader br = new BufferedReader(isr);
            String s;
            while ((s = br.readLine()) != null) {
                result.append(System.lineSeparator()).append(s);
            }
            br.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result.toString();
    }

    /**
     * 控制读几行
     *
     * @param txtpath    路径
     * @param lineNumber 读取的行数
     * @return
     */
    public static String readTxt(String txtpath, int lineNumber) {
        File file = new File(txtpath);
        StringBuilder result = new StringBuilder();
        try {
            BufferedReader br = new BufferedReader(new FileReader(file));
            String str;
            for (int i = 0; i < lineNumber; i++) {
                if ((str = br.readLine()) == null) {
                    break;
                }
                result.append(str);
            }
            br.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result.toString();
    }

    /**
     * 读取指定行
     *
     * @param txtpath
     * @param lineNumber
     * @return
     */
    public static String readLine(String txtpath, int lineNumber) {
        File file = new File(txtpath);
        StringBuilder result = new StringBuilder();
        try {
            BufferedReader br = new BufferedReader(new FileReader(file));
            String str;
            int i = 1;
            while ((str = br.readLine()) != null) {
                if (i == lineNumber) {
                    result.append(str);
                    break;
                }
                i++;
            }
            br.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result.toString();
    }

    /**
     * 读取指定行(多行)
     *
     * @param txtpath     路径
     * @param lineNumbers 要取数据的行数
     * @return 数据列表(有序list,对应数组)
     */
    public static LinkedList<String> readLine(String txtpath, int[] lineNumbers) {
        LinkedList<String> list = new LinkedList<>();
        File file = new File(txtpath);
        try {
            BufferedReader br = new BufferedReader(new FileReader(file));
            String str;
            int i = 1;
            while ((str = br.readLine()) != null) {
                for (int k = 0; k < lineNumbers.length; k++) {
                    if (i == lineNumbers[k]) {
                        list.add(str);
                    }
                }
                i++;
            }
            br.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return list;
    }

    /**
     * 读取指定行(多行)
     *
     * @param txtpath     路径
     * @param targetLines 要取数据的行数
     * @return 数据列表(有序list,对应数组)
     */
    public static JSONObject readLine(String txtpath, JSONObject targetLines) {
        JSONObject result = new JSONObject();
        File file = new File(txtpath);
        try {
            BufferedReader br = new BufferedReader(new FileReader(file));
            StringBuilder total = new StringBuilder();
            String str;
            int i = 1;
            while ((str = br.readLine()) != null) {
                for (String key : targetLines.keySet()) {
                    if (targetLines.getInteger(key) == i) {
                        String value = str.replaceAll((char) 12288 + "", "").replaceAll(":", ":").replaceAll(" ", "");
                        result.put(key, value);
                    }
                }
                total.append(str).append("\n");
                i++;
            }
            br.close();
            result.put("content", total.toString());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 读取所有返回LIST
     *
     * @param txtpath 路径
     * @return 数据列表(有序list,对应数组)
     */
    public static LinkedList<String> readLine(String txtpath) {
        LinkedList<String> list = new LinkedList<>();
        File file = new File(txtpath);
        try {
            BufferedReader br = new BufferedReader(new FileReader(file));
            String str;
            while ((str = br.readLine()) != null) {
                list.add(str);
            }
            br.close();

        } catch (Exception e) {
            e.printStackTrace();
        }
        return list;
    }


 

    public static void createAndWrite(String content, String filePath) {
        BufferedWriter out = null;
        try {
            File file = new File(filePath);
            if (!file.exists()) {
                file.getParentFile().mkdirs();
                file.createNewFile();
            }
            //编码格式可自己更换
            out = new BufferedWriter(new OutputStreamWriter(
                    new FileOutputStream(filePath, true), "UTF-8"));
            out.write(content + "\r\n");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();

            }
        }
    }

}

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

stweaver

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值