前言
我們提供的服務(wù)有:成都網(wǎng)站制作、成都做網(wǎng)站、微信公眾號開發(fā)、網(wǎng)站優(yōu)化、網(wǎng)站認(rèn)證、大化ssl等。為近1000家企事業(yè)單位解決了網(wǎng)站和推廣的問題。提供周到的售前咨詢和貼心的售后服務(wù),是有科學(xué)管理、有技術(shù)的大化網(wǎng)站制作公司
最近線上誤操作了一個數(shù)據(jù),由于是直接修改的數(shù)據(jù)庫,所有唯一的恢復(fù)方式就在MySQL的binlog。binlog使用的是ROW模式,即受影響的每條記錄都會生成一個sql。同時利用了binlog2sql項目。
MySQL Binary Log也就是常說的bin-log, ,是mysql執(zhí)行改動產(chǎn)生的二進(jìn)制日志文件,其主要作用有兩個:
* 數(shù)據(jù)回復(fù)
* 主從數(shù)據(jù)庫。用于slave端執(zhí)行增刪改,保持與master同步。
binlog基本配置和格式
binlog基本配置
binlog需要在mysql的配置文件的mysqld節(jié)點中進(jìn)行配置:
# 日志中的Serverid server-id = 1 # 日志路徑 log_bin = /var/log/mysql/mysql-bin.log # 保存幾天的日志 expire_logs_days = 10 # 每個binlog的大小 max_binlog_size = 1000M #binlgo模式 binlog_format=ROW # 默認(rèn)是所有記錄,可以配置哪些需要記錄,哪些不記錄 #binlog_do_db = include_database_name #binlog_ignore_db = include_database_name
查看binlog狀態(tài)
binlog的三種格式
1.ROW
針對行記錄日志,每行修改產(chǎn)生一條記錄。
優(yōu)點:上下文信息比較全,恢復(fù)某條誤操作時可以直接在日志中查找到原文信息,對于主從復(fù)制支持好。
缺點:輸出非常大,如果是Alter語句將產(chǎn)生大量的記錄
格式如下:
DELETE FROM `back`.`sys_user` WHERE `deptid`=27 AND `status`=1 AND `account`='admin' AND `name`='張三' AND `phone`='18200000000' AND `roleid`='1' AND `createtime`='2016-01-29 08:49:53' AND `sex`=2 AND `email`='sn93@qq.com' AND `birthday`='2017-05-05 00:00:00' AND `avatar`='girl.gif' AND `version`=25 AND `password`='ecfadcde9305f8891bcfe5a1e28c253e' AND `salt`='8pgby' AND `id`=1 LIMIT 1; #start 4 end 796 time 2018-10-12 17:03:19
2.STATEMENT
針對sql語句的,每條語句產(chǎn)生一條記錄
優(yōu)點:產(chǎn)生的日志量比較小,主從版本可以不一致
缺點:主從有些語句不能支持,像自增主鍵和UUID這種類型的
格式如下:
delete from `sys_role`;
3.MIX
結(jié)合了兩種的優(yōu)點,一般情況下都采用STATEMENT模式,對于不支持的語句采用ROW模式
轉(zhuǎn)換成sql
mysql自帶的mysqlbinlog
由于binlog是二進(jìn)制的,所以需要先轉(zhuǎn)換成文本文件,一般可以采用Mysql自帶的mysqlbinlog轉(zhuǎn)換成文本。
mysqlbinlog --no-defaults --base64-output='decode-rows' -d room -v mysql-bin.011012 > /root/binlog_2018-10-10
參數(shù)說明
mysqlbinlog: unknown variable 'default_character_set=utf8mb4'
binlog的基本塊如下:
# at 417750 #181007 1:50:38 server id 1630000 end_log_pos 417844 CRC32 0x9fc3e3cd Query thread_id=440109962 exec_time=0 error_code=0 SET TIMESTAMP=1538877038/*!*/; BEGIN
1、# at 417750
指明的當(dāng)前位置相對文件開始的偏移位置,這個在mysqlbinlog命令中可以作為--start-position的參數(shù)
2、#181007 1:50:38 server id 1630000 end_log_pos 417844 CRC32 0x9fc3e3cd Query thread_id=440109962 exec_time=0 error_code=0
181007 1:50:38指明時間為18年10月7號1:50:38,serverid也就是你在配置文件中的配置的,end_log_pos 417844,這個塊在417844結(jié)束。thread_id執(zhí)行的線程id,exec_time執(zhí)行時間,error_code錯誤碼
3、SET TIMESTAMP=1538877038/!/;
BEGIN
具體的執(zhí)行語句
一行記錄產(chǎn)生的日志如下所示
# at 417750
#181010 9:50:38 server id 1630000 end_log_pos 417844 CRC32 0x9fc3e3cd Query thread_id=440109962 exec_time=0 error_code=0
SET TIMESTAMP=1539136238/*!*/;
BEGIN
/*!*/;
# at 417844
#181010 9:50:38 server id 1630000 end_log_pos 417930 CRC32 0xce36551b Table_map: `goods`.`good_info` mapped to number 129411
# at 417930
#181010 9:50:38 server id 1630000 end_log_pos 418030 CRC32 0x5827674a Update_rows: table id 129411 flags: STMT_END_F
### UPDATE `goods`.`good_info`
### WHERE
### @1='2018:10:07' /* DATE meta=0 nullable=0 is_null=0 */
### @2=9033404 /* INT meta=0 nullable=0 is_null=0 */
### @3=1 /* INT meta=0 nullable=0 is_null=0 */
### @4=8691108 /* INT meta=0 nullable=0 is_null=0 */
### @5=9033404 /* INT meta=0 nullable=0 is_null=0 */
### @6=20 /* LONGINT meta=0 nullable=0 is_null=0 */
### @7=1538877024 /* TIMESTAMP(0) meta=0 nullable=0 is_null=0 */
### SET
### @1='2018:10:07' /* DATE meta=0 nullable=0 is_null=0 */
### @2=9033404 /* INT meta=0 nullable=0 is_null=0 */
### @3=1 /* INT meta=0 nullable=0 is_null=0 */
### @4=8691108 /* INT meta=0 nullable=0 is_null=0 */
### @5=9033404 /* INT meta=0 nullable=0 is_null=0 */
### @6=21 /* LONGINT meta=0 nullable=0 is_null=0 */
### @7=1538877024 /* TIMESTAMP(0) meta=0 nullable=0 is_null=0 */
# at 418030
#181010 9:50:38 server id 1630000 end_log_pos 418061 CRC32 0x468fb30e Xid = 212760460521
COMMIT/*!*/;
# at 418061
一行記錄產(chǎn)生的日志如上所示。以SET TIMESTAMP=1539136238/*!*/;
開始,以COMMIT/*!*/;
結(jié)尾。我們可以根據(jù)兩個at指明的位置來限定范圍。
注意一條記錄開始的SET TIMESTAMP之前的# at 417750和結(jié)尾的COMMIT之后的# at 418061
利用binlog2sql
binlog2sql官網(wǎng)介紹:從MySQL binlog解析出你要的SQL。根據(jù)不同選項,你可以得到原始SQL、回滾SQL、去除主鍵的INSERT SQL等。
基本使用如下:
python binlog2sql.py -hlocalhost -P3306 -udev -p'\*' -d room -t room_info --start-file='mysql-bin.011012' --start-position 129886892 --stop-position 130917280 > rollback.sql
具體的使用我就不講解了github上講解的十分清楚,主要看下很多用來篩選的條件,比如起止時間--start-datetime/--stop-datetime,表名限定-t,數(shù)據(jù)庫限定-d,語句限定--sql-type,主要說說我遇到的一些問題。
mysql的binlog模式
這里需要設(shè)置為ROW,因為ROW模式有原來的信息,如果可以直接利用binlog2sql反向生成回滾sql,如果是STATEMENT無法生成,需要利用的mysql定時備份的文件再去做回滾
恢復(fù)數(shù)據(jù)的具體操作
因為當(dāng)時線上執(zhí)行的是一條update語句,沒有唯一鍵索引的。導(dǎo)致有兩千多條記錄被更新。語句如下:
update room_info set status=1 where status=2;
mysqlbinlog --no-defaults -v --base64-output='decode-rows' -d room --start-datetime='2018-10-10 9:00:00' --stop-datetime='2018-10-10 10:00:00' mysql-bin.011012>temp.sql
zip temp.zip temp.sql && sz temp.zip
取回文件在本地用文本工具如vscode分析,里面有正則匹配,根據(jù)你改動過的特征,比如我有個房間號888888,這個不應(yīng)該被修改,你就查看這個房間號的修改記錄,ROW模式的語句是Where在前,set在后。利用正則room_id=888888.*show_state=1.*AND show_state=2
很快就能匹配到。我當(dāng)時的語句影響了兩千多條記錄,你根據(jù)找到的語句去找開始的SET TIMESTAMP=1539136238
的位置之前的at和結(jié)尾的COMMIT之后的at。
python binlog2sql.py -hlocalhost -P3306 -udev -p'*' -d room -t room_info -B --start-file='mysql-bin.011012' --start-position 129886892 --stop-position 130917280 > rollback.sql
另外
因為我這邊是一條update影響多條的情況,如果是帶唯一鍵的情況下,影響的只有一條記錄,完全沒必要這么麻煩,直接利用binlog2sql帶上-d和-t參數(shù)限定數(shù)據(jù)庫和表,然后利用grep來查找,直接可以得出對應(yīng)的sql。mysqlbinlog少了一個限定表和限定語句的功能。比如精確到一張表的Delete語句,能減少很多的數(shù)據(jù),能快速定位。
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,如果有疑問大家可以留言交流,謝謝大家對創(chuàng)新互聯(lián)的支持。