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