解析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时导致大量数据错误恢复的办法 ...
随机推荐
- Unity3D中的SendMessage使用(消息传递的三种方法)
概述 Unity提供的消息推送机制可以非常方便我们的脚本开发,它实现的是一种伪监听者模式,利用的是反射机制. 常用函数 关于消息推送,常用的函数有三个:”SendMessage“.”SendMessa ...
- 【计算机视觉】阶编码本模型(Multi phase codebook model)
转自:http://www.cnblogs.com/xrwang/archive/2012/04/24/MPCBBGM.html 多阶编码本模型(Multi phase codebook model) ...
- java script 的注释与分号
// 单行注释 /**/多行注释 在js 中 变量.函数和操作符都是区分大小写的 什么是标识符 变量.函数.属性的名字.或者函数的参数. 变量的命名规范:不能以数字开头. 变量声明: var nam ...
- 听说这样可以加快oracle入表速度
oracle 用occi编程的时候,批量提交使用绑定变量的方式,主要瓶颈再sql语句解析上,改成merge into后效率没有变化,但是使用绑定变量方法,能加快速度
- Hbase 0.92.1 Replication
原集群 服务器名称 服务 sht-sgmhadoopnn-01 Master,NameNode,JobTracker sht-sgmhadoopdn-01 RegionServer,DataNode, ...
- Spring(一)--Spring简介
Spring简介 1. Spring的特点 Spring (春天,绿色) 容器 01.Java EE开发者的春天,大大简化了代码量 02.使用IOC来降低主业务之间的耦合度 03.使用AOP来降低主 ...
- Cause: org.xml.sax.SAXParseException: The content of elements must consist of well-formed character data or markup.
Caused by: org.apache.ibatis.builder.BuilderException: Error creating document instance. Cause: org ...
- springboot笔记-文件上传
使用 Spring Boot 和 Thymeleaf 上传文件 Spring Boot 利用 MultipartFile 的特性来接收和处理上传的文件,本示例前端页面使用 Thymeleaf 来处理. ...
- springboot笔记-thymeleaf
简介:Thymeleaf 是⾯向 Web 和独⽴环境的现代服务器端 Java 模板引擎,能够处理 HTML.XML.JavaScript.CSS 甚至纯文本.Thymeleaf 的作用域在 HTML ...
- Python笔记(二)
python笔记 函数式编程 函数 函数是Python内建支持一种封装(将大段代码拆成函数) 通过函数的调用,可以将复制的任务分解. 函数式编程(Functional Programming) 计算机 ...