美文网首页
yichen阿里云rdsmysql8.0误删数据根据mysql-

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

作者: yichen_china | 来源:发表于2021-12-01 15:27 被阅读0次

    准备工作
    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
    

    相关文章

      网友评论

          本文标题:yichen阿里云rdsmysql8.0误删数据根据mysql-

          本文链接:https://www.haomeiwen.com/subject/hbmsxrtx.html