开发人员误操作执行了update批量修改了数据库中某个表某个字段的值,现在想通过binlog去恢复执行update那个表之前的数据
因为不是整库恢复,所以 先通过mysqlbinlog对binlog文件进行转化,转化出来的sql为整库的操作语句,然后再对需要恢复的表的操作语句进行提取,就是在提取的时候 遇到问题,不知道怎么提取,有高人指教一下吗?
我的操作步骤如下:
1.将二进制日志转化成sql文件,修改数据的时间确定大致在11:55之前,所以上面导出11:55之前的数据操作;
/usr/local/mysql/bin/mysqlbinlog -d test1 --base64-output=decode-rows -v  --stop-datetime='2017-02-23 11:55:00' mysql_bin.000001 > test1.sql贴出关键部分sql内容:
# at 319
#170217 10:28:23 server id 1  end_log_pos 392 CRC32 0x48479b8f  Query thread_id=4 exec_time=0 error_code=0
SET TIMESTAMP=1487298503/*!*/;
BEGIN
/*!*/;
# at 392
#170217 10:28:23 server id 1  end_log_pos 445 CRC32 0xdb09ce03  Table_map: `test1`.`account` mapped to number 70
# at 445
#170217 10:28:23 server id 1  end_log_pos 547 CRC32 0xf2e41ab9  Update_rows: table id 70 flags: STMT_END_F
### UPDATE `test1`.`account`
### WHERE
###   @1='zhangsan'
### SET
###   @1='ceshi'
### UPDATE `test1`.`account`
### WHERE
###   @1='lisi'
### SET
###   @1='ceshi'
### UPDATE `test1`.`account`
### WHERE
###   @1='wanger'
### SET
###   @1='ceshi'
### UPDATE `test1`.`account`
### WHERE
###   @1='mazi'
### SET
###   @1='ceshi'
# at 547
#170217 10:28:23 server id 1  end_log_pos 578 CRC32 0x5ee48b32  Xid = 22
COMMIT/*!*/;
DELIMITER ;
# End of log file
ROLLBACK /* added by mysqlbinlog */;2.筛选出误操作表的的语句:(网上看别人是这么操作的 可以筛选出来,我这样筛选却不对 不知道为什么)
more test1.sql |grep  --ignore-case -E 'update' -A2 -B2|grep account
我筛选出的结果是:
[root@redis-slave data]# more test1.sql |grep  --ignore-case -E 'update' -A2 -B2|grep account
#170217 10:28:23 server id 1  end_log_pos 445 CRC32 0xdb09ce03  Table_map: `test1`.`account` mapped to number 70
### UPDATE `test1`.`account`
### UPDATE `test1`.`account`
### UPDATE `test1`.`account`
### UPDATE `test1`.`account`
这结果明显是不对的 有人告知一下为什么吗?
如果筛选出来误操作表的语句的话,就可以
more test1.sql |grep  --ignore-case -E 'update' -A2 -B2|grep account  > update.sql
然后执行update.sql就可以对误操作表进行恢复了

解决方案 »

  1.   

    [root@c65muban data]# cat 1
    ### UPDATE `test1`.`account`
    ### WHERE
    ###   @1='zhangsan'
    ### SET
    ###   @1='ceshi'
    [root@c65muban data]# sed  's/###//g;s/SET/limit 1;/g;s/@1='"'"ceshi"'"'//g;s/WHERE/SET/g;s/@1/name/g' 1
     UPDATE `test1`.`account`
     SET
       name='zhangsan'
     limit 1;
       
    [root@c65muban data]# 
      

  2.   

    网上那些grep a b 的做法都是错的。你无法保证完整的sql语句位于匹配行的前后几行。我以前写过一个php脚本,可以试下,也有一些情况没处理,比如依赖数据库自增的set insertid。
    <?php
    $sql_file="out.sql"; //完整的sql文件
    $tab_name="mod_son"; //要提取的表
     
    $sql = new SplFileObject($sql_file);
    $log=false;
    foreach($sql as $line){ //逐行读取
     if ( preg_match("/^(SET TIMESTAMP=)/", $line) ) { //当前行找到匹配
    $timestamp=$line;
     }
     if ( preg_match("/(create|delete|replace|insert|alter|update)([A-Z_\-\.\s\`]+){$tab_name}/i", $line) ) { //当前行找到匹配
    file_put_contents($tab_name."_out.sql", $timestamp, FILE_APPEND); //时间戳
    $log=true;
     }
     if ($log) {
    file_put_contents($tab_name."_out.sql", $line, FILE_APPEND);
     }
     if ( $log && preg_match("/\/\*\!\*\/;/",$line) ){
    $log=false;
     }
    }
     
    echo "导出完毕!\n";
      

  3.   

    binlog2sql https://github.com/danfengcao/binlog2sql
      

  4.   

    https://github.com/danfengcao/binlog2sql  里面的筛选指定表日志好像没用,