mysqlbinlog結合sed命令恢復數據

1、環境說明

使用mysqlbinlog搭配sed命令完美還原

MySQL版本號:5.6.X及5.7.X;

mysql必須開啓binlog,並且mysql的binlog最好是Row模式;

mysql數據庫指定字符集位utf8,同時表的字符集也得爲utf8,否則在mysqlbinlog 解析出來的sql文件對於中文漢字的會出現亂碼,導致最後恢復數據到線上的表中報錯。

滿足以上條件這樣可以極大的保證數據恢復的機率。

當然把控好數據庫的權限問題,禁止採用不加where條件的delete 和update語句,以及禁止採用drop,truncate纔是從根源保證數據安全行之有效的辦法。


查看當前的binlog文件:

show master status;

image.png

image.png

找到binllog文件路徑下,再次之前需要確認一下你誤操作的大概時間,因爲我們要通過時間範圍來搜索日誌,執行命令如下:

mysqlbinlog  --base64-output=decode-rows  -v -v --start-datetime='2019-10-17 14:40:00' --stop-datetime='2019-10-17 14:50:00'  /data/mysql_data/binlog.000004 |grep -C 30 "UPDATE `test1`.`zx_scores`"


找到我們誤操作的update 語句,記錄下sql上面 # at 開頭後面的數字4558 (這個標記應該是事務的行號),OK,繼續執行命令:

mysqlbinlog  --no-defaults  --base64-output=decode-rows  -v -v  /data/mysql_data/binlog.000004|sed -n '/# at 4558/,/COMMIT/p'  >/data/soft/update_test1.sql

將這串事務從# at 4558開始到COMMIT之間的行全部提取出來到/data/soft/update_test1.sql裏。

到此處,我們已經拿到了需要還原的sql語句,根據導出的sql語句進行sed命令替換,還原到修改之前sql語句。


第一個sed命令作用:將where 和set位置對調

cp -a update_test1.sql update_test1_sed1.sql

sed -i '/WHERE/{:a;N;/SET/!ba;s/\([^\n]*\)\n\(.*\)\n\(.*\)/\3\n\2\n\1/}' update_test1_sed1.sql

解釋:

/WHERE/{:a;N;/SET/!ba;

:a;        #創建一個labela;

N;        #追加下一個輸入行到讀取行的末尾,讀入到模式空間

/SET/!ba;  #如果不是/SET/,返回a,也就是重複讀,一直讀到/SET/之前(buffer的內容是WHERE\n.......\nSET)


s/([^\n])\n(.)\n(.*)/\3\n\2\n\1/ 這塊可以分三部分來讀

    第1步:

        s  #替換命令,例如s/a/b  將a替換爲b

    第2步:

        \([^\n]*\)\n\(.*\)\n\(.*\)

        \        #轉義字符

        [^\n]* == buffer中的where

        (.*\)    #單符號(.)匹配除換行符以外的單個字符,*同上;

         [^\n]*\  #代表非換行符(回車)開頭,*表示匹配零或多個字符

        \n       #換行

    第3步

        \3\n\2\n\1  

        \3  == 內存中的set,第三個括號中的內容

        \2  == 內存中原來where與set之間的內容,第二個括號中的內容

        \1  == 內存中的where,第一個括號中的內容


第二個sed 命令作用: 1.把字符串### 替換成 空格 2.把/*往後的內容 替換成,

cp -a update_test1_sed1.sql update_test1_sed2.sql

sed -i 's/### //g;s/\/\*.*/,/g' update_test1_sed2.sql

解釋:

s/### //g         #將### 替換成空串,

    \                #轉義字符

    \/\*.*             #匹配/*之後出換行符外所有內容


第三個sed 命令作用: 把字符串包含@7的行中的全部(,)換成空格

cp -a update_test1_sed2.sql update_test1_sed3.sql

sed -i /@7/s/,//g update_test1_sed3.sql

解釋:

/@7/       #匹配包含@7的行

 s/,//       #將,替換爲空串

    g        #全部替換


第四個sed 命令作用: 1.把WHERE 至@7之間的所有逗號,替換成AND 2.#.* 就是把#在的行替換爲空格 3.把匹配到的COMMIT, 替換爲空格

cp -a update_test1_sed3.sql update_test1_sed4.sql

sed -i '/WHERE/{:a;N;/@7/!ba;s/,/AND/g};s/#.*//g;s/COMMIT,//g' update_test1_sed4.sql

解釋:

/WHERE/{:a;N;/@7/!ba;s/,/AND/g}      #將WHERE至@7之間的行尾的(,)替換爲(AND)

        s/#.*//g                    #將#號開頭的整行字符替換爲空串。

        s/COMMIT,//g              #將(COMMIT,)替換爲空行;


第五個sed 命令作用:刪除所有的空行

cp -a update_test1_sed4.sql update_test1_sed5.sql

sed -i '/^$/d' update_test1_sed5.sql

解釋:

/^$/          #查找緩存內容中所有的空行

    d         #刪除


第六個sed 命令作用:1.在where語句後@7最後一個字段加(;)2. 把@1,@2.....@6,@7替換爲對應的zx_scores表的列名

cp -a update_test1_sed5.sql update_test1_sed6.sql

sed  -i -r  '/WHERE/{:a;N;/@7/!ba;s/(@7=.*)/\1\;/g}' update_test1_sed6.sql

sed -i 's/@1/id/g;s/@2/titles/g;s/@3/icon/g;s/@4/integral/g;s/@5/isdefault/g;s/@6/create_time/g;s/@7/day/g' update_test1_sed6.sql


數據格式化

cat update_test1_sed6.sql |tr "\n" " "  >update_test1_tr1.sql

將所有的換行替換成空格,此處用tr命令,因我的數據量比較大,tr執行效率相對較高,也可以用sed命令sed -i ':label;N;s/\n/ /;b label' update_test1_sed6.sql,效果都是一樣的


cp -a update_test1_tr1.sql update_test1_sed7.sql

sed -i 's/\;/ LIMIT 1\;\n/g' update_test1_sed7.sql

在每一個;前面加上 LIMIT 1,後面加上換行符

恢復到MySQL

image.png

image.png

到此處mysqlbinlog結合sed命令恢復數據庫數據介紹完畢。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章