站点被攻击了,数据表丢了两张,而且是很重要的明细表,真是魂淡啊!没办法了,必须先恢复数据,平息老板+客户的怒气。
万幸的是,数据库有做差异备份,备份了一天之前的数据。先把这部分数据提取,恢复了,心率和血压顿时下降了一半。最多最多就丢了半天的数据,应该不会卖身也赔不起了。
接下来,才是重头戏,恢复这半天的数据,从早上4点到下午16点,这12个小时的数只能从bin-log上想办法。首先,找到这一天的日志文件(因为这一天日志文件涉及好几个,这边简化过程,只以一个文件来说,暂且命名为bin-log-0821)。
第一步:先们bin-log-0821转为可视明文:
mysqlbinlog --set-charset=utf8 --database=db_name --start-datetime="2016-8-21 4:00:00" --stop-datetime="2016-8-21 16:00:00" bin-log-0821 > log.sql
第二步:得到了log.sql,我们要把log.sql中,我们需要的两张表(暂且命名table1和table2)相关的sql语句提取出来。可是就在这一步,本菜遇到了一个麻烦事。就是INSERT和UPDATE语句,有可能跨行,无法很便提取出来。如果用grep -i table1 log.sql > log_result.sql,一碰到跨行的记录只有UPDATE `table1` SET 没下文了。。。
加上本菜的Shell功力又不强,所以在这个环节卡了好久。最好,通过网上一顿狂搜,搜到了以下办法:
sed -n '/^INSERT /,/;/p' log.sql > log_insert.sql
sed -n '/^UPDATE /,/;/p' log.sql > log_update.sql
最后得到的结果格式是:
UPDATE `table1` SET
//此处省略字段设置
WHERE ...
/*!*/;
第三步:看到上面的格式,曙光终于在眼前了。本菜用PHP写了段代码,把需要的SQL都过滤了出来:
$fp=fopen('log_insert.sql','rb+'); if(!$fp) exit('file err'); while(!feof($fp)) { $sql=''; $str=fgets($fp,1024); if(strstr($str,'table1') || strstr($str,'table2')) { $sql.=$str; while(!feof($fp)) { $str=fgets($fp,1024); if(strstr($str,'/*')) { break; } $sql.=$str; } $db->query($sql); } } fclose($fp);
至此,万事大吉矣。终于恢复了需要的数据,一个周日血压升高后又回降,真心好刺激啊。