闪回脚本:mysql_rollback.py
发表于:2026-11-01 作者:千家信息网编辑
千家信息网最后更新 2026年11月01日,#!/bin/env python# -*- coding:utf-8 -*-import os,sys,re,getoptimport MySQLdbhost = '127.0.0.1'user =
千家信息网最后更新 2026年11月01日闪回脚本:mysql_rollback.py
#!/bin/env python# -*- coding:utf-8 -*-import os,sys,re,getoptimport MySQLdbhost = '127.0.0.1'user = ''password = ''port = 3306start_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# ----------------------------------------------------------------------------------------# 功能:初始化binlog里的所有表名和列名,用全局字典result_dict来储存每个表有哪些列# ----------------------------------------------------------------------------------------def init_col_name(): global result_dict global pri_dict global fileContent result_dict = {} pri_dict = {} table_list = re.findall('`.*`\\.`.*`',fileContent) table_list = list(set(table_list)) #table_list 为所有在这段binlog里出现过的表 print "正在初始化列名....." for table in table_list: sname = table.split('.')[0].replace('`','') tname = table.split('.')[1].replace('`','') #连接数据库获取列和列id try: conn = MySQLdb.connect(host=host,user=user,passwd=password,port=int(port)) cursor = conn.cursor() cursor.execute("select ordinal_position,column_name \ from information_schema.columns \ where table_schema='%s' and table_name='%s' " %(sname,tname)) result=cursor.fetchall() if result == () : print 'Warning:'+sname+'.'+tname+'已删除' #sys.exit() result_dict[sname+'.'+tname]=result cursor.execute("select ordinal_position,column_name \ from information_schema.columns \ where table_schema='%s' and table_name='%s' and column_key='PRI' " %(sname,tname)) pri=cursor.fetchall() #print pri pri_dict[sname+'.'+tname]=pri cursor.close() conn.close() except MySQLdb.Error, e: try: print "Error %d:%s" % (e.args[0], e.args[1]) except IndexError: print "MySQL Error:%s" % str(e) sys.exit() #print result_dict #print pri_dict# ----------------------------------------------------------------------------------------# 功能:拼凑回滚sql,逆序# ----------------------------------------------------------------------------------------def gen_rollback_sql(): global only_primary fileOutput = open(output, 'w') #先将文件根据'--'分块,每块代表一个sql area_list=fileContent.split('--\n') #逆序读取分块 print "正在开始拼凑sql....." for area in area_list[::-1]: #由于一条sql可能影响多行,每个sql又可以分成多个逐条执行的sql sql_list = area.split('##') #先将pos点和timestamp传入输出文件中 for sql_head in sql_list[0].splitlines(): sql_head = '#'+sql_head+'\n' fileOutput.write(sql_head) #逐条sql进行替换更新,逆序 for sql in sql_list[::-1][0:-1]: try: 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) tablename_pos = 2 table_name = rollback_sql.split()[tablename_pos].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:]: i = int(col[1:]) - 1 rollback_sql = rollback_sql.replace(col+'=', 'AND ' + result_dict[table_name][i][1]+'=',1) # 如果only_primary开启且存在主键,where条件里就只列出主键字段 if int(only_primary) == 1 and pri_dict[table_name] <> (): sub_where = '' for primary in pri_dict[table_name]: primary_name = primary[1] for condition in rollback_sql.split('WHERE', 1)[1].splitlines(): if re.compile('^\s*'+primary_name).match(condition) or re.compile('^\s*AND\s*'+primary_name).match(condition): sub_where = sub_where + condition + '\n' sub_where = re.sub('^\s*AND', '', sub_where, 1) rollback_sql = rollback_sql.split('WHERE', 1)[0] + 'WHERE\n' + sub_where 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) tablename_pos = 1 table_name = rollback_sql.split()[tablename_pos].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:]: i = int(col[1:]) - 1 rollback_sql = rollback_sql.replace(col+'=', ',' + result_dict[table_name][i][1]+'=', 1).replace(col+'=','AND ' +result_dict[table_name][i][1]+'=') # 如果only_primary开启且存在主键,where条件里就只列出主键字段 if int(only_primary) == 1 and pri_dict[table_name] <> (): sub_where = '' for primary in pri_dict[table_name]: primary_name = primary[1] for condition in rollback_sql.split('WHERE', 1)[1].splitlines(): if re.compile('^\s*' + primary_name).match(condition) or re.compile('^\s*AND\s*'+primary_name).match(condition): sub_where = sub_where + condition + '\n' sub_where = re.sub('^\s*AND', '', sub_where, 1) rollback_sql = rollback_sql.split('WHERE', 1)[0] + 'WHERE\n' + sub_where if sql.split()[0] == 'DELETE': rollback_sql = re.sub('^DELETE FROM', 'INSERT INTO', sql, 1) rollback_sql = re.sub('WHERE\n', 'SET\n', rollback_sql, 1) tablename_pos = 2 table_name = rollback_sql.split()[tablename_pos].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:]: i = int(col[1:]) - 1 rollback_sql = rollback_sql.replace(col+'=', ',' + result_dict[table_name][i][1]+'=',1) rollback_sql = re.sub('\n$',';\n',rollback_sql) #print rollback_sql fileOutput.write(rollback_sql) except IndexError,e: print "Error:%s" % str(e) sys.exit() print "done!"def usage(): help_info="""==========================================================================================Command line options : --help # OUT : print help info -f, --binlog # 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 binlog_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()if __name__ == '__main__': getopts_parse_binlog() init_col_name() gen_rollback_sql()
文件
正在
功能
参数
逆序
逗号
错误
字段
条件
逐条
先将
代表
全局
多个
字典
密码
数据
数据库
文件名
用户
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
互联网科技公司
伟宏互联网科技
互联网科技公司起名
互联网佳科技有限公司
北京互联网科技公司
互联网医疗科技
平安科技 互联网
华中科技大学互联网
互联网科技公司招聘
北京三清互联网科技
字节跳动和互联网科技
承德科技产业互联网发展
金融科技与互联网金融相同和不同
福建科技产业互联网发展
互联网新科技动漫ppt素材
互联网企业科技类企业如何做账
2021世界互联网领先科技成果发布
互联网科技企业商标注意事项
东风日产互联网科技公司叫什么
科技美学互联网 艺术
国智互联网科技
互联网是不是新科技
深圳科技互联网
互联网科技公司怎么样
云电互联网科技
北京禾田雨橡互联网科技
互联网科技类展会
阿里巴巴算科技企业还是互联网
广州千川互联网科技有限公司
互联网科技机房