問題場景
最近在使用binlog2sql進行MySQL數(shù)據(jù)庫誤操作恢復(fù)的時候莹汤,遇到了一個錯誤:
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x8b in position 0: invalid start byte
原因
通過檢查源碼和測試發(fā)現(xiàn)罩缴,這個問題是由于源代碼中溢陪,在生成回滾語句時,首先將回滾語句保存到臨時文件中盯孙,然后按照block讀取臨時文件羽利,倒序輸出語句。
最后生成的回滾語句和原始的執(zhí)行順序是相反的序苏,即后執(zhí)行的語句先回滾手幢。
在Python3環(huán)境中,需要使用utf-8對文件內(nèi)容進行解碼忱详,在解碼時围来,如果一個block的內(nèi)容是以b
開頭的,就會出現(xiàn)解碼失敗報錯的情況。
處理方案
要修復(fù)這個問題监透,可以更新代碼的以下部分
也可以直接下載更新后的代碼 binlog2sql
def print_rollback_sql(self, filename):
"""print rollback sql from tmp_file"""
# 首先嘗試原始方法
try:
with open(filename, "rb") as f_tmp:
batch_size = 1000
i = 0
for line in reversed_lines(f_tmp):
print(line.rstrip())
if i >= batch_size:
i = 0
if self.back_interval:
print('SELECT SLEEP(%s);' % self.back_interval)
else:
i += 1
# 如果使用原始方法遇到問題桶错,讀取整個文件進行倒序輸出
# 占用內(nèi)存可能上升
except:
with open(filename, "rb") as f_tmp:
s = f_tmp.read()
if sys.version > '3':
s_decode = s.decode("utf-8")
s_list = s_decode.split("\n")
s_list.reverse()
batch_size = 1000
i = 0
for line in s_list:
print(line.rstrip())
if i >= batch_size:
i = 0
if self.back_interval:
print('SELECT SLEEP(%s);' % self.back_interval)
else:
i += 1
binlog2sql 說明
從MySQL binlog解析出你要的SQL。根據(jù)不同選項胀蛮,你可以得到原始SQL院刁、回滾SQL、去除主鍵的INSERT SQL等粪狼。
用途
- 數(shù)據(jù)快速回滾(閃回)
- 主從切換后新master丟數(shù)據(jù)的修復(fù)
- 從binlog生成標(biāo)準(zhǔn)SQL黎比,帶來的衍生功能
環(huán)境
* Python 2.7, 3.4+
* MySQL 5.6, 5.7
安裝
shell> git clone https://github.com/danfengcao/binlog2sql.git && cd binlog2sql
shell> pip install -r requirements.txt
使用
MySQL server必須設(shè)置以下參數(shù):
[mysqld]
server_id = 1
log_bin = /var/log/mysql/mysql-bin.log
max_binlog_size = 1G
binlog_format = row
binlog_row_image = full
user需要的最小權(quán)限集合:
select, super/replication client, replication slave
建議授權(quán)
GRANT SELECT, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO
權(quán)限說明
- select:需要讀取server端information_schema.COLUMNS表,獲取表結(jié)構(gòu)的元信息鸳玩,拼接成可視化的sql語句
- super/replication client:兩個權(quán)限都可以阅虫,需要執(zhí)行'SHOW MASTER STATUS', 獲取server端的binlog列表
- replication slave:通過BINLOG_DUMP協(xié)議獲取binlog內(nèi)容的權(quán)限
基本用法
解析出標(biāo)準(zhǔn)SQL
shell> python binlog2sql.py -h127.0.0.1 -P3306 -uadmin -p'admin' -dtest -t test3 test4 --start-file='mysql-bin.000002'
輸出:
INSERT INTO `test`.`test3`(`addtime`, `data`, `id`) VALUES ('2016-12-10 13:03:38', 'english', 4); #start 570 end 736
UPDATE `test`.`test3` SET `addtime`='2016-12-10 12:00:00', `data`='中文', `id`=3 WHERE `addtime`='2016-12-10 13:03:22' AND `data`='中文' AND `id`=3 LIMIT 1; #start 763 end 954
DELETE FROM `test`.`test3` WHERE `addtime`='2016-12-10 13:03:38' AND `data`='english' AND `id`=4 LIMIT 1; #start 981 end 1147
解析出回滾SQL
shell> python binlog2sql.py --flashback -h127.0.0.1 -P3306 -uadmin -p'admin' -dtest -ttest3 --start-file='mysql-bin.000002' --start-position=763 --stop-position=1147
輸出:
INSERT INTO `test`.`test3`(`addtime`, `data`, `id`) VALUES ('2016-12-10 13:03:38', 'english', 4); #start 981 end 1147
UPDATE `test`.`test3` SET `addtime`='2016-12-10 13:03:22', `data`='中文', `id`=3 WHERE `addtime`='2016-12-10 12:00:00' AND `data`='中文' AND `id`=3 LIMIT 1; #start 763 end 954
選項
mysql連接配置
-h host; -P port; -u user; -p password
解析模式
--stop-never 持續(xù)解析binlog〔桓可選颓帝。默認(rèn)False,同步至執(zhí)行命令時最新的binlog位置窝革。
-K, --no-primary-key 對INSERT語句去除主鍵购城。可選虐译。默認(rèn)False
-B, --flashback 生成回滾SQL瘪板,可解析大文件,不受內(nèi)存限制漆诽∥昱剩可選。默認(rèn)False厢拭。與stop-never或no-primary-key不能同時添加兰英。
--back-interval -B模式下,每打印一千行回滾SQL供鸠,加一句SLEEP多少秒畦贸,如不想加SLEEP,請設(shè)為0楞捂”』担可選。默認(rèn)1.0寨闹。
解析范圍控制
--start-file 起始解析文件胶坠,只需文件名,無需全路徑 鼻忠。必須涵但。
--start-position/--start-pos 起始解析位置杈绸。可選矮瘟。默認(rèn)為start-file的起始位置瞳脓。
--stop-file/--end-file 終止解析文件〕合溃可選劫侧。默認(rèn)為start-file同一個文件。若解析模式為stop-never哨啃,此選項失效烧栋。
--stop-position/--end-pos 終止解析位置∪颍可選审姓。默認(rèn)為stop-file的最末位置;若解析模式為stop-never祝峻,此選項失效魔吐。
--start-datetime 起始解析時間,格式'%Y-%m-%d %H:%M:%S'莱找〕昴罚可選。默認(rèn)不過濾奥溺。
--stop-datetime 終止解析時間辞色,格式'%Y-%m-%d %H:%M:%S'「《ǎ可選相满。默認(rèn)不過濾。
對象過濾
-d, --databases 只解析目標(biāo)db的sql壶唤,多個庫用空格隔開雳灵,如-d db1 db2≌⒖可選。默認(rèn)為空琳省。
-t, --tables 只解析目標(biāo)table的sql迎吵,多張表用空格隔開,如-t tbl1 tbl2针贬』鞣眩可選。默認(rèn)為空桦他。
--only-dml 只解析dml蔫巩,忽略ddl。可選圆仔。默認(rèn)False垃瞧。
--sql-type 只解析指定類型,支持INSERT, UPDATE, DELETE坪郭。多個類型用空格隔開个从,如--sql-type INSERT DELETE⊥嵛郑可選嗦锐。默認(rèn)為增刪改都解析。用了此參數(shù)但沒填任何類型沪曙,則三者都不解析奕污。
--trans-number 解析的事務(wù)數(shù)量,可選液走。默認(rèn)無限制 這個是我個人修改后代碼中的功能碳默,源代碼是沒有的