通过java流从日志中提取sql脚本
前提
忘记备份数据,和开启MySQL的binlog记录日志。导致一些数据误删没办法快速恢复,只能通过系统日志去查看这些操作从中捞出INSERT INTO xxxx(表名)语句。再去重新执行。由于每天都会有日志文件所以导致要筛选的日志过于庞大耗费时间超长,所以使用JAVA写了个小型脚本用于筛选所需信息。
package com.mlzhang;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class FileTest {
private static final String FILE_PATH = "D:\\Debug-2021-06-16-1.log"; //文件路径
public static void main(String[] args) {
readText(FILE_PATH);
}
public static void readText(String filePath) {
//通过路径创建文件
File file = new File(filePath);
if (file.isFile() && file.exists()) {
try {
//文件编码为gbk,这里做个转换
InputStreamReader isr = new InputStreamReader(new FileInputStream(file), "gbk");
//字符缓冲流
BufferedReader br = new BufferedReader(isr);
String lineTxt;
List<String> list = new ArrayList<>();
int record = 0;
while ((lineTxt = br.readLine()) != null) {
if(record == 1){
list.add(lineTxt); //record 为1是 这行数据加入list集中
}
String regex = "INSERT INTO table"; //需要筛选的信息
boolean contains = lineTxt.contains(regex); //每读一行数据判断一下是否包含该信息
if(contains){
record = 1; //预示下一行数据加入list中
}else {
record = 0;
}
}
if(list.size() != 0){
List<String> collect = list.stream().map(s -> {
String str = "debug";
int index = s.indexOf(str);
String substr = s.substring(index + 5);
String str2 = "2021-06-16";
int index2 = substr.indexOf(str2);
String substr2 = substr.substring(index2 + 10);
int index3 = substr2.indexOf(str2);
return substr2.substring(index3 - 18);
}).collect(Collectors.toList()); //截取多余字符结果集
List<String> replace = replace(collect); //替换多余字符拼接成可执行sql集
writeText(replace); //写入新数据
}
br.close();
} catch (IOException e) {
e.printStackTrace();
System.out.println("文件读取错误!");
}
}else {
System.out.println("文件不存在!");
}
}
public static void writeText(List<String> list){
File file = new File(FILE_PATH);
if(file.exists()){
try {
file.createNewFile();
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file)));
list.forEach(s -> {
try {
bw.write(s);
bw.newLine(); //写完换行
bw.flush();
} catch (IOException e) {
e.printStackTrace();
}
});
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 替换成可以执行的sql;
* @param list insert 值
*/
public static List<String> replace(List<String> list){
//这里是去替换掉sql中多余的字符,最后组装成我们所需要的可执行的SQL。
return list.stream().map(s -> {
String all = s.replaceAll("\\(Timestamp\\)", "'")
.replaceAll("\\(Double\\)", "")
.replaceAll("\\(Integer\\),\\s", "\\),('")
.replaceAll("2021-06", "'2021-06")
.replaceAll("\\(String\\)", "'")
.replaceAll("\\(Integer\\)", "\\);");
String sql = "INSERT INTO table(xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx) \n" +
"VALUES ";
return sql + "('" + all;
}).collect(Collectors.toList());
}
}
以上就是脚本代码。
IO流简单介绍
因为文本的读和写使用了IO流所以这里放张JAVA体系中IO流结构图。
java中的IO分类:
根据数据的流向分为: 输入流和输出流。
输入流 :把数据从其他设备上读取到内存中的流。
输出流 :把数据从内存 中写出到其他设备上的流。
根据数据的类型分为:字节流和字符流。
字节流 :以字节为单位,读写数据的流。
字符流 :以字符为单位,读写数据的流。