MySQL利用binlog恢复误操作数据
在人工手动进行一些数据库写操作的时候(比方说数据订正),尤其是一些不可控的批量更新或删除,通常都建议备份后操作。不过不怕万一,就怕一万,有备无患总是好的。在线上或者测试环境误操作导致数据被删除或者更新后,想要恢复,一般有两种方法。
方法一、利用最近的全量备份+增量binlog备份,恢复到误操作之前的状态,但是随着数据量的增大,binlog的增多,恢复起来很费时。
方法二、如果binlog的格式为row,那么就可以将binlog解析出来生成反向的原始SQL
以下是利用方法二写的一个python脚本binlog_rollback.py,可利用此脚本生成反向的原始SQL。
说明:
0、前提是binlog的格式为row
1、要恢复的表操作前后表结构没有发生变更,否则脚本无法解析
2、只生成DML(insert/update/delete)的rollback语句
3、最终生成的SQL是逆序的,所以最新的DML会生成在输入文件的最前面,并且带上了时间戳和偏移点,方便查找目标
4、需要提供一个连接MySQL的只读用户,主要是为了获取表结构
5、如果binlog过大,建议带上时间范围,也可以指定只恢复某个库的SQL
6、SQL生成后,请务必在测试环境上测试恢复后再应用到线上
脚本代码
#!/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
# ----------------------------------------------------------------------------------------
# 功能:获取参数,生成相应的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 “参数输入有误!!!!!”
options = []
if options == [] or options[0][0] in (“--help”):
usage()
sys.exit()
print “正在获取参数。..。.”
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
评论
查看更多