yichen阿里云rdsmysql8.0误删数据根据mysql-

2021-12-01  本文已影响0人  yichen_china

准备工作
1.操作的机器需要安装python3.6或其他版本
2.操作机器需要安装mysql8.0,mysql/bin目录下有mysqlbinlog工具文件
3.把我写的python脚本放到服务器中
开始干活
b.python 内容

#_*_ coding:utf-8 _*_
# 作者yichen qq2782268022 
import sys
import os
import io
import re
binlogfile = sys.argv[1]
database_name = sys.argv[2]
table_name = sys.argv[3]
print('--database="'+database_name+'"')
# binlogfile="b472in.txt"
rootname="/www/server/mysql/bin/mysqlbinlog"
def format_binlog():
    os.system(rootname+' --start-datetime="2021-11-25 16:48:00" --skip-gtids --stop-datetime="2021-11-25 19:50:00" --database='+database_name+' -v -v  --base64-output=DECODE-ROWS   /www/server/mysql/bin/'+binlogfile+'  > '+binlogfile+'.log')
#需要处理的语句
# confMethod=["INSERT","UPDATE","DELETE","ALTER","CREATE","REPLACE"]
confMethod=["INSERT","UPDATE"]
def isMethod(method,row):
    if method=="INSERT" and "### INSERT" == row[0:10]:
        return True
    elif method =="UPDATE" and  "### UPDATE"  == row[0:10]:
        return True
    elif method=="DELETE" and  "### DELETE"  == row[0:10]:
        return True
    elif method =="ALTER" and  "ALTER" == row[0:5]:
        return True
    elif method =="CREATE" and  "CREATE" == row[0:5]:
        return True
    elif method =="REPLACE"   and "REPLACE"== row[0:7]:
        return True
    else:
        return False
def getMethod(methodArr,row):
    for method in methodArr:
        if isMethod(method, row):
            return method
    return None
def pickupbinlog():
    f = io.open(binlogfile+'.log','r')
    fw = io.open(binlogfile+'_.log','a')
    # 记录上一行首3个字符
    priv_str = ''
    #段落分割线首行
    priv_line = ''
    goal_flag = 0
    # 测试到某行停止执行
    nub=0
    # where条件部分
    whereRow=""
    # # set部分
    # setRow=""
    # 部分标识
    stateRow="" #WHERE
    # stateAll="UPDATE DELETE INSERT ALTER"
    method="" #UPDATE
    # # 首部分
    # headRow=""
    # # 其他部分
    # otherRow=""
    rowData="" 
    lastState=0
    nub=1
    for row in f:
        lineMethod=getMethod(confMethod,row)
        # if(method=="UPDATE"):
       ### create|### replace|### insert|### alter|### update
        # # 处理首行 对批量input不准确
        linRow=row
        if lineMethod!=None:

            # 上条语句如果没结束,添加;字符作为结束符
            if(len(method)>1):

                if(rowData.find(";")==-1):
                    if method =="INSERT":
                        fw.write(");\n")
                    elif method == "UPDATE" or method=="DELETE":
                        
                        fw.write(" WHERE "+whereRow+"\n")
                    else:
                        fw.write(";\n")
                # if priv_str !="###":
                    # fw.write(priv_line)
                    
            method=""
            stateRow=""
            if database_name in row and table_name in row:
               
                # if priv_str !="###":
                    # fw.write(priv_line)
               
                if(row.find("`"+database_name+"`.")):
                    row=row.replace("`"+database_name+"`.","")
                goal_flag=1
                if lineMethod=="INSERT":
                    method="INSERT"
                    rowData=row.replace("### INSERT INTO","INSERT IGNORE INTO")+" VALUES("
                    # print(rowData)
                    # if(headRow.find("`"+database_name+"`.")):
                    # # headRow=headRow.translate(str.maketrans('','',"`"+database_name+"`."))
                    # headRow=headRow.replace("`"+database_name+"`.","")
                elif lineMethod=="UPDATE":
                    method="UPDATE"
                    rowData=row.replace("### UPDATE","UPDATE IGNORE")
                    #  print(row)
                elif lineMethod=="DELETE":
                    method="DELETE"
                    # print(row)
                    rowData=row.replace("### DELETE","DELETE")
                elif lineMethod=="ALTER":
                    method="ALTER"
                    rowData = row
                elif lineMethod =="CREATE":
                    method="CREATE"
                    rowData=row.replace("### CREATE","CREATE")
                elif lineMethod=="REPLACE":
                    method="REPLACE"
                    rowData = row
                else:
                    rowData = row
                rowData=rowData.replace("### ","")
            else:
                method=""
                rowData="";
                stateRow=""
                goal_flag=0
        elif  row[0:3] != '###' and priv_str == '###':
            stateRow=""
            # 上条语句如果没结束,添加;字符作为结束符
            if(len(method)>1):
                if(rowData.find(";")==-1):
                    if method =="INSERT":
                        fw.write(");\n")
                    elif method == "UPDATE" or method=="DELETE":
                        fw.write(" WHERE "+whereRow+"\n")
                    else:
                        fw.write(";\n")
                fw.write(row);
            rowData=""
            method="";
            goal_flag=0
        #     if database_name in row and table_name in row:
        # # if row[0:3] == '###' and database_name in row and table_name in row:
        #         goal_flag = 1
        # 处理目标操作
        elif row[0:3] == '###' and goal_flag==1:
             # 删除最后吃出现的注释/*之后部分
            if row.rfind( '/*' )>0:
                row=row[ 0 : row.rfind( '/*' ) ]
            # 记录本行 下次首行进行判断
            if( "### SET"==row[0:7]):
                stateRow="SET"
                if(method!="INSERT"):
                    rowData=row[4:len(row)]
                # rowData=row[4:len(row)]
            elif("### WHERE" == row[0:9]):
                stateRow="WHERE"
                rowData=""
            else:
                rowlen=len(row)
                # print ("处理目标操作")
                #这是我的特殊需求去除结尾空格
                # row=row.rstrip()
                if("WHERE" == stateRow):
                    rowData="";
                    if("@1=" in row):
                        whereRow=row[4:rowlen]+";"
                elif("SET" == stateRow):
                    # print(row)
                    if("@" in row):
                        if method=="INSERT":
                            end=row.find( '=' )
                            if end>0:
                                # 对于一个节点@1 判断
                                if row.find("@1=")>-1 and row.find("@1=")<10:
                                    
                                    rowData=row[ end+1: len(row) ]
                                else:
                                    rowData=","+row[ end+1: len(row) ]
                                    # rowData="("+setRow+",";
                                    # fw.write(rowData);
                               
                                # setRow+row+","
                        elif method=="UPDATE":
                            # 对于一个节点下匹配input操作,根据重复@1 判断
                            if row.find("@1=")>-1 and row.find("@1=")<10:
                                 rowData=row[4:rowlen]
                            else:
                                 rowData=","+row[4:rowlen]

                        else:
                            rowData=row[4:rowlen]
                else:
                    rowData=row[4:rowlen]
            # print(row)
        elif goal_flag==1:
            if "SET @@SESSION.GTID_NEXT" in row or "BEGIN" ==row[0:5] or "SET TIMESTAMP" == row[0:13]:
                rowData=""
            else:
                rowData=row
            
        if(len(rowData)>1):
            fw.write(rowData)
            rowData=""
        priv_line = linRow
        priv_str = priv_line[0:3]
        # elif(len(row)>2):
        #     priv_str = priv_line[0:3]
            # fw.write(row)
            
        # if nub>7:
        #     # print(setRow)
        #     break;
    f.close()
    fw.close()

if __name__ == '__main__':
    # python2.7 pickupbinlog.py mysql-bin.001051 dbname tablename
    # python3 pickupbinlog.py mysql-bin.001051 dbname tablename
    format_binlog()
    pickupbinlog()

在b.python 内容里需要修改下/www/server/mysql/bin/mysqlbinlog 的参数。根据你的需求参考mysqlbinlog官方文档配置。我的案例是按启止时间和数据库名去查找的
然后 执行命令

python b.py mysqlbinlog日志文件名 数据库名 数据库的表名

#python.py 可以配置想要处理的方法参数, confMethod=["INSERT","UPDATE","DELETE","ALTER","CREATE","REPLACE"]
python b.py mysql-bin.000473 dbname tablename

查看关键字 你要的区域,获得所在行号,记录下来

cat mysql-bin.000473_.log -n |grep -A 50 "ALTER" | head -n 200

截取第一个行到行号的内容

sed -n '1,110095p'  mysql-bin.000472_.log>b472a.log

截取行号 到结尾的内容

sed -n "110095,&p"  mysql-bin.000472_.log>b472b.log

把结果内容的@字段替换成数据库对应的字段
用sql语句执行

#假设数据库名:beiyao-zt-test
#假设数据表名:'zt_product_base'
set @irowa  =0 ;
set @irowb  =51 ;
SELECT GROUP_CONCAT(CONCAT("s/@",@irowa:=@irowa+1,'=/',COLUMN_NAME,'=/g') SEPARATOR ";") as a FROM information_schema.COLUMNS 
WHERE TABLE_SCHEMA = 'beiyao-zt-test' AND TABLE_NAME = 'zt_product_base'

得到如下@1--对应字段的字符串

s/@1=/id=/g;s/@2=/brand_name=/g;

linux命令 替换生成数据库可执行的sql文件

sed  's/@1=/id=/g;s/@2=/upc=/g;' b472a.log>b472a.sql

然后导入sql文件就可以啦
备用一个php文件

<?php
ini_set("error_reporting","E_ALL & ~E_NOTICE");
$sql_file="mysql-bin.000472"; //完整的sql文件
$tab_name="`beiyaozhongtai`.`zt_product_base`"; //要提取的表
 
$sql = new SplFileObject($sql_file);
$log=false;
foreach($sql as $line){ //逐行读取

 if ( preg_match("/^(#211125 )/", $line) ) { //当前行找到匹配
    $timestamp=$line;
 }
  if ( preg_match("/(replace|alter)([A-Z_\-\.\s\`]+){$tab_name}/i", $line) ) { //当前行找到匹配
//   if ( preg_match("/(create|delete|replace|insert|alter|update)([A-Z_\-\.\s\`]+){$tab_name}/i", $line) ) { //当前行找到匹配
//  if ( preg_match("/(### create|replace|### insert|alter|### update)([A-Z_\-\.\s\`]+){$tab_name}/i", $line) ) { //当前行找到匹配
    // print_r($timestamp."\r\n");
    file_put_contents($sql_file."_out.sql", $timestamp, FILE_APPEND); //时间戳
    $log=true;
 }
 if ($log) {
    file_put_contents($sql_file."_out.sql", $line, FILE_APPEND);
 }
 if ( $log && preg_match("/\/\*\!\*\/;/",$line) ){
    $log=false;
 }
}
 
echo "导出完毕!\n";

几个参数

 if ( preg_match("/^(#211125 )/", $line) ) { //当前行找到匹配
#211125 这个参数需要根据实际binlog文件修改

执行命令

php b.php
上一篇下一篇

猜你喜欢

热点阅读