MySQL利用binlog恢復(fù)誤操作數(shù)據(jù)
在人工手動進(jìn)行一些數(shù)據(jù)庫寫操作的時候(比方說數(shù)據(jù)訂正),尤其是一些不可控的批量更新或刪除,通常都建議備份后操作。不過不怕萬一,就怕一萬,有備無患總是好的。在線上或者測試環(huán)境誤操作導(dǎo)致數(shù)據(jù)被刪除或者更新后,想要恢復(fù),一般有兩種方法。
方法一、利用最近的全量備份+增量binlog備份,恢復(fù)到誤操作之前的狀態(tài),但是隨著數(shù)據(jù)量的增大,binlog的增多,恢復(fù)起來很費時。
方法二、如果binlog的格式為row,那么就可以將binlog解析出來生成反向的原始SQL
以下是利用方法二寫的一個python腳本binlog_rollback.py,可利用此腳本生成反向的原始SQL。
說明:
0、前提是binlog的格式為row
1、要恢復(fù)的表操作前后表結(jié)構(gòu)沒有發(fā)生變更,否則腳本無法解析
2、只生成DML(insert/update/delete)的rollback語句
3、最終生成的SQL是逆序的,所以最新的DML會生成在輸入文件的最前面,并且?guī)狭藭r間戳和偏移點,方便查找目標(biāo)
4、需要提供一個連接MySQL的只讀用戶,主要是為了獲取表結(jié)構(gòu)
5、如果binlog過大,建議帶上時間范圍,也可以指定只恢復(fù)某個庫的SQL
6、SQL生成后,請務(wù)必在測試環(huán)境上測試恢復(fù)后再應(yīng)用到線上
腳本代碼
#!/bin/env python
# -*- coding:utf-8 -*-
import os,sys,re,getopt
import MySQLdb
host = ‘127.0.0.1’
user = ‘’
password = ‘’
port = 3306
start_datetime = ‘1971-01-01 00:00:00’
stop_datetime = ‘2037-01-01 00:00:00’
start_position = ‘4’
stop_position = ‘18446744073709551615’
database = ‘’
mysqlbinlog_bin = ‘mysqlbinlog -v’
binlog = ‘’
fileContent = ‘’
output=‘rollback.sql’
only_primary = 0
# ----------------------------------------------------------------------------------------
# 功能:獲取參數(shù),生成相應(yīng)的binlog解析文件
# ----------------------------------------------------------------------------------------
def getopts_parse_binlog():
global host
global user
global password
global port
global fileContent
global output
global binlog
global start_datetime
global stop_datetime
global start_position
global stop_position
global database
global only_primary
try:
options, args = getopt.getopt(sys.argv[1:], “f:o:h:u:p:P:d:”, [“help”,“binlog=”,“output=”,“host=”,“user=”,“password=”,“port=”,“start-datetime=”, \
“stop-datetime=”,“start-position=”,“stop-position=”,“database=”,“only-primary=”])
except getopt.GetoptError:
print “參數(shù)輸入有誤?。。。?!”
options = []
if options == [] or options[0][0] in (“--help”):
usage()
sys.exit()
print “正在獲取參數(shù)。..。.”
for name, value in options:
if name == “-f” or name == “--binlog”:
binlog = value
if name == “-o” or name == “--output”:
output = value
if name == “-h” or name == “--host”:
host = value
if name == “-u” or name == “--user”:
user = value
if name == “-p” or name == “--password”:
password = value
if name == “-P” or name == “--port”:
port = value
if name == “--start-datetime”:
start_datetime = value
if name == “--stop-datetime”:
stop_datetime = value
if name == “--start-position”:
start_position = value
if name == “--stop-position”:
stop_position = value
if name == “-d” or name == “--database”:
database = value
if name == “--only-primary” :
only_primary = value
if binlog == ‘’ :
print “錯誤:請指定binlog文件名!”
usage()
if user == ‘’ :
print “錯誤:請指定用戶名!”
usage()
if password == ‘’ :
print “錯誤:請指定密碼!”
usage()
if database 《》 ‘’ :
condition_database = “--database=” + “‘” + database + “’”
else:
condition_database = ‘’
print “正在解析binlog.。..。”
fileContent=os.popen(“%s %s --base64-output=DECODE-ROWS --start-datetime=‘%s’ --stop-datetime=‘%s’ --start-position=‘%s’ --stop-position=‘%s’ %s\
|grep ‘###’ -B 2|sed -e ‘s/### //g’ -e ‘s/^INSERT/##INSERT/g’ -e ‘s/^UPDATE/##UPDATE/g’ -e ‘s/^DELETE/##DELETE/g’ ” \
%(mysqlbinlog_bin,binlog,start_datetime,stop_datetime,start_position,stop_position,condition_database)).read()
#print fileContent
評論
查看更多