利用MySQL日志模擬恢復數據變化軌跡(中)
在上篇《利用MySQL日志模擬恢復數據變化軌跡》中,我們已經介紹了我們方案的大致思路,其原理就是某網友提到的撈日志方式。
通過mysqlbinlog解析binlog之后,我們可以發現對我們有用的信息都是以###開頭,通過正則表達式匹配,我們就可以得到。
在日志中有@1,@2等字符, 這是代表表結構的字段名,即@1表示表中第一個字段,@2表示表中第二個字段等。然后我們通過查詢INFORMATION_SCHEMA.COLUMNS表可以找到表的所有字段,然后一一替換掉即可。對于INSERT 和 DELETE兩種操作,其數據行只有一份,而UPDATE有兩份數據行。對此,我們需要第二份。
例如:
表結構信息
binlog信息
我們需要將其翻譯成完全可執行的sql:insert into a (id, num) values (1, 199);
在截取字段值時,我們遇到一下幾個坑:
1、字段值為日期類型。在日志中保存的格式為 @1=2012-12-04 13:14:35,此時,必須將2012-12-04 13:14:35加上引號。
2、負數。負數在日志中保存的格式為 @1=-1 (4294967295), 此時,我們其實只需要‘-1’即可。
3、轉義字符集。日志當中顯示的字段值信息與數據庫中字段值信息一致,但是mysql在插入數據庫是做了轉義,導致日志中的內容不能馬上截取直接使用。對此,我們修改了mysqlbinlog這個工具,讓其解析出來的文本是未被轉義的。例舉幾個:
root@test 09:50:58>insert into tx values(‘a\’b');
root@test 09:56:47>insert into tx values(‘a\tb’);
root@test 10:06:01>insert into tx values(‘a\bb’);
root@test 10:06:04>insert into tx values(‘a\0b’);
——————————————————-
原版
### INSERT INTO test.tx
### SET
### @1=’a'b’
### INSERT INTO test.tx
### SET
### @1=’a\x09b’
### INSERT INTO test.tx
### SET
### @1=’a\x08b’
### INSERT INTO test.tx
### SET
### @1=’a\x00b’
——————————————————-
修改版
### INSERT INTO test.tx
### SET
### @1=’a\’b’
### INSERT INTO test.tx
### SET
### @1=’a\tb’
### INSERT INTO test.tx
### SET
### @1=’a\bb’
### INSERT INTO test.tx
### SET
### @1=’a\0b’
具體內容可以參照:https://bugs.launchpad.net/percona-server/+bug/949965
4、雙字節字符問題。
碰到一次解析binlog得到
·······
### @1=’休閑女鞋白黃粉黒’
······
解析出來的sql是insert into a values (‘黒\’),插回到數據庫報錯。原因是多了一個轉義字符,在回去查看binlog時,并沒有這個多余的轉義字符‘\’。仔細看后,發現這并不是那個‘黑’,前者的十六進制是(FC5C),后者的十六進制是(BADA)。查看ASCII碼表后得知,5C對應的字符是‘\’,而在第三類問題上已經對轉義字符集修改,導致在解析出來的時候變成了 @1=’黒\’。
5、未發現問題。這個就需要我們大家更多的測試實踐才能發現了。
PS:下篇文章中將獻上已經修改過的mysqlbinlog以及工具腳本的代碼。