如果数据库误操作想恢复数据。可以试试下面这个脚本。前提是执行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回滚脚本的更多相关文章

  1. 【MySQL】MySQL事务回滚脚本

    MySQL自己的 mysqlbinlog | mysql 回滚不好用,自己写个简单脚本试试: 想法是用mysqlbinlog把需要回滚的事务区域从mysql-bin.file中找到,然后通过脚本再插入 ...

  2. 【MySQL】MySQL回滚工具

    1.mysqlbinlog把事务从binlog中导出 2.从导出的binlog中找到要回滚的事务,去掉第一个DML语句前和最后一个DML语句后与DML无关的binlog信息 3.在目录中新建一个tab ...

  3. 【linux】【jenkins】jenkins构建、mvn或者npm打包、docker运行、失败自动回滚脚本

    小白对jenkins运维的使用有点简单的想法,这里开个记录贴记录下. 由于未找到jenkins构建失败后执行其他脚本的插件,也暂时没有使用其他运维工具.所以想自己写一个shell脚本,一是方便其他人使 ...

  4. mysql回滚日志

    一.回滚日志(undo log) 1.作用 保存了事务发生之前的数据的一个版本,可以用于回滚,同时可以提供多版本并发控制下的读(MVCC),也即非锁定读 2.内容 逻辑格式的日志,在执行undo的时候 ...

  5. 关于MySQL回滚机制

    在事务中,每个正确的原子操作都会被顺序执行,直到遇到错误的原子操作,此时事务会将之前的操作进行回滚.回滚的意思是如果之前是插入操作,那么会执行删 除插入的记录,如果之前是update操作,也会执行up ...

  6. .net中使用mysql回滚和sqlserver回滚的区别

    关于sqlserver事务和mysql事务 首先这是一种方法 public static int GetExecteQuery()        {            SqlConnection ...

  7. shell自动化一键部署脚本,秒级一键回滚脚本

    #!/bin/bash # Node List PRE_LIST="192.168.222.163" # 预生产环境节点 GROUP1_LIST= ROLLBACK_LIST=&q ...

  8. SQL SERVER 生成MYSQL建表脚本

    /****** Object: StoredProcedure [dbo].[GET_TableScript_MYSQL] Script Date: 06/15/2012 13:05:14 ***** ...

  9. 误删数据库怎么办?mysql 回滚,撤销操作,恢复数据

    刚刚不小心把数据库删掉了,于是想着上网上找找有没有可以恢复数据库的方法,没想到还真有,除了备份以外,还有以下方法. 在mysql有时执行了错误的update或者delete时导致大量数据错误恢复的办法 ...

随机推荐

  1. Ubuntu安装并使用emacs

    1. sudo add-apt-repository ppa:kelleyk/emacs 2. sudo apt update sudo apt install emacs26 3.安装完成,查看em ...

  2. 【VS开发】动态创建ActiveX控件

    bool CCollectDataDlgDlg::CreateMyCtrl(LPRECT lpRect, UINT nID, CWnd *pParent) {  CLSID clsid;  wstri ...

  3. Connection is read-only. Queries leading to data modification are not allowed 错误原因

    因为我再spring 中使用了AOP进行事务管理,有如下配置 <tx:advice id="txAdvice" transaction-manager="trans ...

  4. [转帖]/proc/sys/net/ipv4/ 下参数理解

    /proc/sys/net/ipv4/ 下参数理解,方便服务器优化 2017年06月02日 16:52:27 庞叶蒙 阅读数 3065 https://blog.csdn.net/pangyemeng ...

  5. BATJ的常见java面试题

    JAVA基础 JAVA中的几种基本数据类型是什么,各自占用多少字节. String类能被继承吗,为什么. 不可以,因为String类有final修饰符,而final修饰的类是不能被继承的,实现细节不允 ...

  6. c++ Convert struct to bytes

    D:\stock\Tskingfromgoogle\src\NetTS\TW.cpp Convert struct  to bytes //Convert struct to bytes 2019/0 ...

  7. MyBatis时间排序问题

    在数据中create_time字段是DateTime类型, 逆向工程后实体类中对应的成员变量类型为Date 时间排序代码为: 测试结果: 时间排序错乱. 解决方法: 1,在数据库创建varchar类型 ...

  8. laravel框架之修改

    //控制器層 public function update(request $request) { $id = $request->get('id'); $data = DB::select(& ...

  9. 组合&多态&封装

    目录 组合&多态&封装 一.组合 1.1什么是组合 1.2 为什么要用组合 1.3 如何使用组合 1.4 继承和组合都在什么时候用 二.多态与多态性 2.1 什么是多态 2.2 如何用 ...

  10. python 利用 smtplib发邮件

    import smtplib from email.mime.text import MIMEText title = "request build error" content ...