解析binlog生成MySQL回滚脚本
如果数据库误操作想恢复数据。可以试试下面这个脚本。前提是执行DML操作。
#!/bin/env python
#coding:utf-8
#Author: Hogan
#Descript : 解析binlog生成MySQL回滚脚本 import getopt
import sys
import os
import re
import pymysql # 设置默认值
host = '127.0.0.1'
port = 3306
user = ''
password = ''
start_datetime = '1971-01-01 00:00:00'
stop_datetime = '2037-01-01 00:00:00'
start_position = ''
stop_position = ''
database = ''
mysqlbinlog = 'mysqlbinlog -v --base64-output=decode-rows '
binlogfile = ''
output = 'rollback.sql' # 提示信息
def usage():
help_info="""==========================================================================================
Command line options :
--help # OUT : print help info
-f, --binlogfile # IN : binlog file. (required)
-o, --outfile # OUT : output rollback sql file. (default 'rollback.sql')
-h, --host # IN : host. (default '127.0.0.1')
-u, --user # IN : user. (required)
-p, --password # IN : password. (required)
-P, --port # IN : port. (default 3306)
--start-datetime # IN : start datetime. (default '1970-01-01 00:00:00')
--stop-datetime # IN : stop datetime. default '2070-01-01 00:00:00'
--start-position # IN : start position. (default '4')
--stop-position # IN : stop position. (default '18446744073709551615')
-d, --database # IN : List entries for just this database (No default value).
--only-primary # IN : Only list primary key in where condition (default 0) Sample :
shell> python rollback.py -f 'mysql-bin.000001' -o '/tmp/rollback.sql' -h 192.168.0.1 -u 'user' -p 'pwd' -P 3307 -d dbname
==========================================================================================""" print(help_info)
sys.exit() # 获取参数,生成binlog解析文件
def getops_parse_binlog():
global host
global user
global password
global port
global database
global start_datetime
global stop_datetime
global start_position
global stop_position
global binlogfile
global only_primary
global fileContent
global output try:
options, args = getopt.getopt(sys.argv[1:], "f:o:h:P:u:p:d", ["help", "binlogfile=","--output=","host=","port=","user=","password=","database=","start-datetime=",
"stop-datetime=","start-position=","stop-position=","only-primary="])
except getopt.GetoptError:
print('参数错误!')
options = []
if options == [] or 'help' in options[0][0]:
usage()
sys.exit()
print("正在获取参数......")
# print(options)
for name, value in options:
if name in ('-f', '--binlogfile='):
binlogfile = value
if name in ('-o', '--output='):
output = value
if name in ('-h', '--host='):
host = value
if name in ('-P', '--port='):
port = value
if name in ('-u', '--user='):
user = value
if name in ('-p', '--password='):
password = value
if name in ('-d', '--database='):
database = 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 == '--only-primary':
only_primary = value
if not binlogfile:
print("错误:请指定binlog文件名")
usage()
if not user:
print("错误:请指定用户名!")
usage()
if not password:
print("错误:请指定密码!")
usage()
if database:
condition_database = "--database='" + database + "'"
else:
condition_database = ''
print("正在解析binlog......")
cmd = ("%s --start-position=%s --stop-position=%s --start-datetime='%s' --stop-datetime='%s' %s %s| grep '###' -B 2 | sed -e 's/### //g' | sed -e 's/^INSERT/##INSERT/g' -e 's/^UPDATE/##UPDATE/g'\
-e 's/^DELETE/##DELETE/g'" % (mysqlbinlog, start_position, stop_position, start_datetime, stop_datetime, binlogfile, condition_database )) fileContent = os.popen(cmd).read() # 初始化binlog里的表名和列名,用全局字典result_dict来存储表名,列名
def init_clo_name():
global result_dict
global col_dict
result_dict = {}
# 统计binlog中出现的所有库名.表名
table_list = list(set(re.findall('`.*`\\.`.*`', fileContent))) for table in table_list:
db_name = table.split('.')[0].strip('`')
table_name = table.split('.')[1].strip('`')
# 连接数据库获取字段id
try:
conn = pymysql.connect(host=host, port=int(port), user=user, password=password)
cursor = conn.cursor()
# 获取字段名,字段position
cursor.execute("select ordinal_position, column_name from information_schema.columns where table_schema='%s' and table_name='%s'" %(db_name,table_name))
result = cursor.fetchall()
if result == ():
print('Warning: ' + db_name + '.' + table_name + '已删除')
result_dict[db_name+'.'+table_name] = result
except pymysql.Error as e:
try:
print("Error %d:%s" % (e.args[0], e.args[1]))
except IndexError:
print("MySQL Error:%s" % str(e))
sys.exit() # 拼接反向生成回滚SQL
def gen_rollback_sql():
# 打开输出文件
fileOutput = open(output, 'w')
print('正在拼凑SQL......')
# 将binlog解析的文件通过'--'进行分割,每块代表一个sql
area_list = fileContent.split('--\n')
# 逆序读取分块
for area in area_list[::-1]:
sql_list = area.split('##')
for sql_head in sql_list[0].splitlines():
sql_head = '#' + sql_head + '\n'
fileOutput.write(sql_head)
# 逐条对SQL进行替换更新,逆序
for sql in sql_list[::-1][:-1]:
try:
# 对insert语句进行拼接
if sql.split()[0] == 'INSERT':
rollback_sql = re.sub('^INSERT INTO', 'DELETE FROM', sql, 1)
rollback_sql = re.sub('SET\n' , 'WHERE\n', rollback_sql, 1)
table_name = rollback_sql.split()[2].replace('`','')
# 获取该SQL所有列
col_list = sorted(list(set(re.findall('@\d+', rollback_sql))))
# 因为第一个列前面没有逗号或者and,所以单独替换
rollback_sql = rollback_sql.replace('@1', result_dict[table_name][0][1] )
# 替换其他列
for col in col_list[1:]:
col_int = int(col[1:]) -1
rollback_sql = rollback_sql.replace(col, 'and '+ result_dict[table_name][col_int][1],1 ) #对update语句进行拼接
if sql.split()[0] == 'UPDATE':
rollback_sql = re.sub('SET\n', '#SET#\n', sql, 1)
rollback_sql = re.sub('WHERE\n', 'SET\n', rollback_sql, 1)
rollback_sql = re.sub('#SET#\n', 'WHERE\n',rollback_sql, 1)
table_name = rollback_sql.split()[1].replace('`','')
# 获取该SQL所有列
col_list = sorted(list(set(re.findall('@\d+', rollback_sql))))
# 因为第一个列前面没有逗号或者and,所以单独替换
rollback_sql = rollback_sql.replace('@1', result_dict[table_name][0][1] )
# 替换其他列
for col in col_list[1:]:
col_int = int(col[1:]) -1
rollback_sql = rollback_sql.replace(col, ','+ result_dict[table_name][col_int][1],1 ).replace(col,'and '+result_dict[table_name][col_int][1]) # 对delete语句进行拼接
if sql.split()[0] == 'DELETE':
rollback_sql = re.sub('^DELETE FROM', 'INSERT INTO', sql, 1)
rollback_sql = re.sub('WHERE', 'SET', rollback_sql, 1)
table_name = rollback_sql.split()[2].replace('`','')
# 获取该SQL所有列
col_list = sorted(list(set(re.findall('@\d+', rollback_sql))))
# 因为第一个列前面没有逗号或者and,所以单独替换
rollback_sql = rollback_sql.replace('@1', result_dict[table_name][0][1] )
# 替换其他列
for col in col_list[1:]:
col_int = int(col[1:]) -1
rollback_sql = rollback_sql.replace(col, ', '+ result_dict[table_name][col_int][1],1 )
#SQL结尾加;
rollback_sql = re.sub('\n$', ';', rollback_sql)
rollback_sql = re.sub('\n', '', rollback_sql)
rollback_sql = re.sub(';', ';\n', rollback_sql)
fileOutput.write(rollback_sql)
except IndexError as e:
print ("Error:%s" % str(e))
sys.exit()
print ("done!") if __name__ == '__main__':
getops_parse_binlog()
init_clo_name()
gen_rollback_sql()
解析binlog生成MySQL回滚脚本的更多相关文章
- 【MySQL】MySQL事务回滚脚本
MySQL自己的 mysqlbinlog | mysql 回滚不好用,自己写个简单脚本试试: 想法是用mysqlbinlog把需要回滚的事务区域从mysql-bin.file中找到,然后通过脚本再插入 ...
- 【MySQL】MySQL回滚工具
1.mysqlbinlog把事务从binlog中导出 2.从导出的binlog中找到要回滚的事务,去掉第一个DML语句前和最后一个DML语句后与DML无关的binlog信息 3.在目录中新建一个tab ...
- 【linux】【jenkins】jenkins构建、mvn或者npm打包、docker运行、失败自动回滚脚本
小白对jenkins运维的使用有点简单的想法,这里开个记录贴记录下. 由于未找到jenkins构建失败后执行其他脚本的插件,也暂时没有使用其他运维工具.所以想自己写一个shell脚本,一是方便其他人使 ...
- mysql回滚日志
一.回滚日志(undo log) 1.作用 保存了事务发生之前的数据的一个版本,可以用于回滚,同时可以提供多版本并发控制下的读(MVCC),也即非锁定读 2.内容 逻辑格式的日志,在执行undo的时候 ...
- 关于MySQL回滚机制
在事务中,每个正确的原子操作都会被顺序执行,直到遇到错误的原子操作,此时事务会将之前的操作进行回滚.回滚的意思是如果之前是插入操作,那么会执行删 除插入的记录,如果之前是update操作,也会执行up ...
- .net中使用mysql回滚和sqlserver回滚的区别
关于sqlserver事务和mysql事务 首先这是一种方法 public static int GetExecteQuery() { SqlConnection ...
- shell自动化一键部署脚本,秒级一键回滚脚本
#!/bin/bash # Node List PRE_LIST="192.168.222.163" # 预生产环境节点 GROUP1_LIST= ROLLBACK_LIST=&q ...
- SQL SERVER 生成MYSQL建表脚本
/****** Object: StoredProcedure [dbo].[GET_TableScript_MYSQL] Script Date: 06/15/2012 13:05:14 ***** ...
- 误删数据库怎么办?mysql 回滚,撤销操作,恢复数据
刚刚不小心把数据库删掉了,于是想着上网上找找有没有可以恢复数据库的方法,没想到还真有,除了备份以外,还有以下方法. 在mysql有时执行了错误的update或者delete时导致大量数据错误恢复的办法 ...
随机推荐
- Zookeeper 假死脑裂
该问题就是服务集群因为网络震荡导致的多主多从问题,解决方案就是设置服务切换的超时时间,但也同时会导致无法达到高可用的要求.
- 事务与Mysql隔离级别
事务 定义: 比如ABCD四个业务,作为一个事务,他们要么一起都执行完毕,要么都不执行.(只要有一个不成功,那么所有的都不可以成功) 四个特性 ACID 原子性(Atomicity) 整个事务中的所有 ...
- Synchronized底层优化(轻量级锁、偏向锁)(二)
一.重量级锁 上篇文章中向大家介绍了Synchronized的用法及其实现的原理.现在我们应该知道,Synchronized是通过对象内部的一个叫做监视器锁(monitor)来实现的.但是监视器锁本质 ...
- zabbix监控大数据
参考: https://github.com/Staroon/zabbix-hadoop-template 支持监控HDFS.NameNode, YARN ResourceManager, Hive, ...
- 小记---------手动执行脚本正常执行,使用crontab定时执行时 不执行
可能出现的原因就是因为crontab不会从用户的/etc/profile文件中读取环境变量,所以就出现 使用定时crontab执行时 无法执行 抛错 所以在使用crontab 定时执行脚本时 在脚本 ...
- Python 的开始
现在的 Linux 上一般都自带有 Python 如果没有,那就下载一个 打开 python 在终端中输入 python ,如果出现了和这差不多的 Python 2.7.15+ (default, O ...
- python 安装 colorama 控制台输出彩色文字
pip install colorama from colorama import Back,Fore,Style # 字体颜色print(Fore.LIGHTBLUE_EX,'HelloWorLd' ...
- 一遍记住 8 种排序算法与 Java 代码实现
☞ 程序员进阶必备资源免费送「21种技术方向!」 ☜ 作者:KaelQ, www.jianshu.com/p/5e171281a387 1.直接插入排序 经常碰到这样一类排序问题:把新的数据插入到已经 ...
- luogu P4382 [九省联考2018]劈配
luogu 我记得我第一次做这道题的时候屁都不会qwq 先考虑第一问,暴力是依次枚举每个人,然后从高到低枚举志愿,枚举导师,能选就选.但是可以发现前面的人选的导师可能会导致后面的人本来可以选到这个志愿 ...
- 解决Linux下SSH超时自动断开
title: 解决Linux下SSH超时自动断开 comments: false date: 2019-08-19 19:22:55 description: Linux 下 SSH 超时自动断开?? ...