• 记录一次数据库的恢复经历


      测试环境下的数据被莫名其妙的修改了,全表更新错误,影响正常的开发。由于没有备份,通过备份无法恢复。只有通过binlog来恢复:

    中间遇到的问题和经历说下

     1).使用root权限,找到mysql的my.cnf目录和binlog目录,找到里面的bin_log.里面含有binglog的日志目录.其实就是通过mysql的命令行界面,输入

    SHOW VARIABLES LIKE '%log_bin%';

    看到的内容类似

    比如我自己的目录:

    my.cnf
    /db/data0/mysql/3306/my.cnf
    binlog
    /db/data0/mysql/3306/binlog/

    2)进入到mysql的 bin目录,使用mysqlbinlog命令

    mysql bin路径:/usr/local/mysql/bin/

    使用binglog 先要查看具体某一天的:可以使用命令
    mysqlbinlog --base64-output=decode-rows -v --start-datetime='2017-12-10 00:00:00' --stop-datetime='2017-12-10 23:01:01' -d 数据库名称 binlog日志路径以及名称

    3)找到 最后一天的positon
    [root@hcloud ~]# mysqlbinlog  /db/data0/mysql/3306/binlog/binlog.000150 

    内容一般如下:

    #160809 5:09:28 server id 1 end_log_pos 2698 Query thread_id=17 exec_time=0 error_code=0
    SET TIMESTAMP=1470733768/*!*/;
    SET @@session.foreign_key_checks=1, @@session.unique_checks=1/*!*/;
    SET @@session.sql_mode=0/*!*/;
    /*!C latin1 *//*!*/;
    SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8/*!*/;
    insert into Test_DB.OneTb values(4,'user4',21),(5,'user5',22),(6,'user6',23)
    /*!*/;
    # at 2698
    #160809 5:19:49 server id 1 end_log_pos 2795 Query thread_id=17 exec_time=0 error_code=0
    SET TIMESTAMP=1470734389/*!*/;
    update Test_DB.OneTb set name='user10'
    /*!*/;
    # at 2795
    #160809 5:30:38 server id 1 end_log_pos 2814 Stop
    DELIMITER ;
    # End of log file
    ROLLBACK /* added by mysqlbinlog */;
    /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/

    如果想要截止到某一天,可以通过以下命令导出:

     mysqlbinlog  --base64-output=decode-rows -v  --stop-position="2698" /db/data0/mysql/3306/binlog/binlog.000150 > Backup_1.sql 

    导入到当前目录,比如:/db/data0/mysql/3306/binlog/Backup_1.sql
    ,此时进入mysql目录,如果服务器有多个mysql服务可以这样登录:(socket目录在my.cnf里面指定了)

    mysql --user=root --port=端口号 --socket=/tmp/mysql.sock -p密码(注意密码前面不要有空格)

    之后进去mysql之后,进入自己的mysql要恢复的数据库,执行以下sql
    source /db/data0/mysql/3306/binlog/Backup_1.sql

    4)如果想要恢复某天到某天的可以使用如下命令:

    mysqlbinlog --base64-output=decode-rows -v --start-datetime="2017-11-06 09:16:54"
    --stop-datetime="2017-11-27 18:00:00" --database=zm_gaiay_net_cn /db/data0/mysql/3306/binlog/binlog.000150
    | /usr/local/mysql/bin/mysql -uroot -port16234 --socket=/tmp/mysql.sock -p1234 -v zm_gaiay_net_cn

    5)如果是update语句全表更新,想要恢复到之前的数据:

    1)找到更改的时间点
    2)使用命令 mysqlbinlog --base64-output=decode-rows -v --start-datetime="2017-11-06 09:16:54"
    --stop-datetime="2017-11-27 18:00:00" /db/data0/mysql/3306/binlog/binlog.000150 > update.sql
    导入到sql文件中

    3)通过shell脚本 替换所有的update语句,shell脚本如下:

    #!/bin/bash
    # by ray
    
    iswhere=1   #判断循环的行的位置,1表示在where后,0表示不再where后
    colNum=0    #计算列数,一般在binlog日志内第一列为@1,第二列为@2一次类推
    whereNum=0  #判断where后面字段出现的次数,便于拼接字符串,第一次出现不适用都会,第二次以后使用逗号拼接
    setNum=0 #判断set后面字段出现的次数,便于拼接字符串,第一次出现不适用都会,第二次以后使用逗号拼接
    
    replaceColumn(){   #把@开头的列替换为列配置文件内的列,安配置文件的顺序执行
         cat $1 | while read line
         do
              colNum=$[${colNum}+1]
              sed -i "s/@${colNum}/${line}/g" ./execSQL.sql  #替换列
         done
    }
    
    getSQL(){   #获取sql
         sql1=''
         sql_result=''
         sql_condition=''
         while read line #读取处理过的binlog日志
         do
              if [[ ${line} =~ 'UPDATE' ]];then     #匹配是否update
                   if [ "${sql1}" != "" ];then
                        echo ${sql1}' '${sql_result}' '${sql_condition}';' >> ./execSQL.sql  #打印sql
                        sql1=''
                        sql_result=''
                        sql_condition=''
                        whereNum=0
                        setNum=0
                   fi
                 sql1=${line}        #拼接sql字符串,获取update
            elif [[ ${line} =~ 'WHERE' ]];then
                 sql_condition=${line}   #拼接字符串,把binlog日志内where后面内容
                 iswhere=1               #判断是否为where,因为要把where和set后面的内容互换
            elif [[ ${line} =~ 'SET' ]];then
                 sql_result=' SET '${sql_result} #拼接字符串
                 iswhere=0
            elif [[ ${iswhere} -eq 1 ]];then            #1为where后面,把binlog日志where后面的内容拼接到sql的set后
                 if [[ ${whereNum} -eq 0 ]];then              #判断where字符串后的字符串是否一次出现
                      sql_result=${sql_result}' '${line}
                      whereNum=1                    #设置为1,表示不是第一次出现
                 elif [[ ${whereNum} -eq 1 ]];then
                      sql_result=${sql_result}', '${line}
                 fi
            elif [[ ${iswhere} -eq 0 ]];then           #判断是否为set后面的字符串
                 if [[ ${setNum} -eq 0 ]];then               #判断set字符串后的字符串是否一次出现
                      sql_condition=${sql_condition}' '${line}
                      setNum=1                     #设置为1,表示不是第一次出现
                 elif [[ ${setNum} -eq 1 ]];then
                      sql_condition=${sql_condition}' and '${line}
                 fi
            fi
         done < $1   #把文件用while循环读取每一行
         echo ${sql1}' '${sql_result}' '${sql_condition}';' >> ./execSQL.sql    #最后一行退出循环,所以要打印最后一行
         echo "commit;" >> ./execSQL.sql
         replaceColumn $2
    }
    
    
    #脚本的入口,调用函数获取内容
    if [ -e $1 ];then  #判断第一个参数是否为文件
         getSQL $1 $2
    else
        echo $1' is not a file!!'
    fi

     4)执行shell脚本  bash getSQL.sh '/tmp/update.sql' "./column.txt" (绝对路径)

    5)执行execSQL.sql有可能会执行不了,如果执行不了,可以通过替换 里面的@1 @2 替换为相应的字段
      中间出现的问题:1.表里面字段有 utf-8mb4无法恢复2.state状态如果是负数,通过binlog转换后会出现诸如-2 (65524) 这样的,需要修改下;

  • 相关阅读:
    数据库中导入json数据
    EntityFrameWork Core创建数据库并且使用
    AutoMapper自动映射框架的使用(一)
    值类型和引用类型
    Windows10家庭版安装docker
    Manjaro Linux系统安装
    STM32之USMART的简单介绍
    DSP28335笔记
    张飞第二部:直流无刷电机 直流电源 电感 热水循环泵系统
    高输入阻抗 低输出阻抗 的意义
  • 原文地址:https://www.cnblogs.com/thinkingandworkinghard/p/8033056.html
Copyright © 2020-2023  润新知