时间:2021-07-01 10:21:17 帮助过:12人阅读
这里注意一个地方,039的转义字符是没有在函数 esc_code 中统一处理,而是单独做另外处理。
转移字符表相见下图:
在处理行记录的时候,要对timestamp的value做处理,添加from_unixtime函数转换。
所以当遇到INT的各种数据类型并且VALUE为负数的时候,需要把 这个范围值去除,才能执行执行undo_sql。
本人喜欢用各种颜色来分类参数(blingbling五颜六色,看着多有趣多精神),所以,按颜色来说明这些参数。
1 --测试环境(请安装pymysql):IP: 192.168.9.242,PORT:3310 ,数据库:flashback,表格:tbevent 2 --具有线上表结构的db:IP:192.168.9.243 PORT:3310 3 4 5 mysql> show global variables like ‘max_allowed_packet‘; 6 +--------------------+----------+ 7 | Variable_name | Value | 8 +--------------------+----------+ 9 | max_allowed_packet | 16777216 | 10 +--------------------+----------+ 11 1 row in set (0.00 sec) 12 13 mysql> set global max_allowed_packet = 1073741824; 14 Query OK, 0 rows affected (0.00 sec) 15 16 [root@sutest244 ~]# mysqlbinlog --start-datetime=‘2017-06-19 09:00:00‘ --stop-datetime=‘2017-06-19 10:00:00‘ --base64-output=decode-rows -v ~/data/mysql/data/mysql-bin.007335 > /tmp/binlog.log 17 18 [root@sutest242 pycharm]# python su_flashback.py -h=127.0.0.1 -P=3310 -u=root -p=**** -f=/tmp/binlog.log -t=flashback.tbevent -oh=192.168.9.244 -oP=3310 -u=root -op=**** -a=0 19 2017-06-19 10:59:39,041 INFO begin to assign values to parameters 20 2017-06-19 10:59:39,041 INFO assign values to parameters is done:host=127.0.0.1,user=root,password=***,port=3310,fpath=/tmp/binlog.log,tbevent=flashback.tbevent 21 2017-06-19 10:59:39,049 INFO MySQL which userd to store binlog event connection is ok 22 2017-06-19 10:59:39,050 INFO assign values to online mysql parameters is done:host=192.168.9.244,user=,password=***,port=3310 23 2017-06-19 10:59:39,054 INFO MySQL which userd to analyse online table schema connection is ok 24 2017-06-19 10:59:39,054 INFO MySQL connection is ok 25 2017-06-19 10:59:39,055 INFO creating table flashback.tbevent to store binlog event 26 2017-06-19 10:59:39,058 INFO created table flashback.tbevent 27 2017-06-19 10:59:39,060 INFO begining to analyze the binlog file ,this may be take a long time !!! 28 2017-06-19 10:59:39,061 INFO analyzing... 29 2017-06-19 11:49:53,781 INFO finished to analyze the binlog file !!! 30 2017-06-19 11:49:53,782 INFO release all db connections 31 2017-06-19 11:49:53,782 INFO All done,check the flashback.tbevent which stored binlog event on host 127.0.0.1 , port 3310 32 33 34 [root@sutest242 pycharm]# python su_flashback.py -h=127.0.0.1 -P=3310 -u=root -p=**** -f=/tmp/binlog.log -t=flashback.tbevent -oh=192.168.9.244 -oP=3310 -u=root -op=**** -a=1 35 2017-06-19 16:30:20,633 INFO begin to assign values to parameters 36 2017-06-19 16:30:20,635 INFO assign values to parameters is done:host=127.0.0.1,user=root,password=***,port=3310,fpath=/tmp/binlog.log,tbevent=flashback.tbevent 37 2017-06-19 16:30:20,865 INFO MySQL which userd to store binlog event connection is ok 38 2017-06-19 16:30:20,866 INFO assign values to online mysql parameters is done:host=192.168.9.244,user=,password=***,port=3310 39 2017-06-19 16:30:20,871 INFO MySQL which userd to analyse online table schema connection is ok 40 2017-06-19 16:30:20,871 INFO MySQL connection is ok 41 2017-06-19 16:30:21,243 INFO There has 347868 transactions ,need 35 batchs ,each batche doing 10000 transactions 42 2017-06-19 16:30:21,243 INFO doing batch : 1 43 2017-06-19 16:31:01,182 INFO doing batch : 2 44 2017-06-19 16:31:16,909 INFO doing batch : 3 45 -------省空间忽略不截图-------------- 46 2017-06-19 16:41:11,287 INFO doing batch : 34 47 2017-06-19 16:41:25,577 INFO doing batch : 35 48 2017-06-19 16:41:44,629 INFO release all db connections 49 2017-06-19 16:41:44,630 INFO All done,check the flashback.tbevent which stored binlog event on host 127.0.0.1 , port 3310
脚本会不定期修复bug,若是感兴趣,可以往github下载:https://github.com/xinysu/mysql.git 中的 mysql_xinysu_flashback 。
1 # -*- coding: utf-8 -*- 2 __author__ = ‘xinysu‘ 3 __date__ = ‘2017/6/15 10:30‘ 4 5 6 7 import re 8 import os 9 import sys 10 import datetime 11 import time 12 import logging 13 import importlib 14 importlib.reload(logging) 15 logging.basicConfig(level=logging.DEBUG,format=‘%(asctime)s %(levelname)s %(message)s ‘) 16 17 import pymysql 18 from pymysql.cursors import DictCursor 19 20 usage=‘‘‘\nusage: python [script‘s path] [option] 21 ALL options need to assign: 22 \033[1;33;40m 23 -h : host, the database host,which database will store the results after analysis 24 -u : user, the db user 25 -p : password, the db user‘s password 26 -P : port, the db port 27 28 -f : file path, the binlog file 29 -t : table name, the table name to store the results after analysis , {dbname}.{tbname}, 30 when you want to store in `test` db and the table name is `tbevent`,then this parameter 31 is test.tbevent 32 \033[1;34;40m 33 -oh : online host, the database host,which database have the online table schema 34 -ou : online user, the db user 35 -op : online password, the db user‘s password 36 -oP : online port, the db port 37 \033[1;32;40m 38 -a : action, 39 0 just analyse the binlog file ,and store sql in table; 40 1 after execute self.dotype=0, execute the undo_sql in the table 41 \033[0m 42 --help: help document 43 \033[1;35;40m 44 Example: 45 analysize binlog: 46 python su_flashback.py -h=127.0.0.1 -P=3310 -u=root -p=*** -f=/tmp/binlog.log -t=flashback.tbevent 47 -oh=192.168.9.244 -oP=3310 -u=root -op=*** 48 -a=0 49 50 flash back: 51 python su_flashback.py -h=127.0.0.1 -P=3310 -u=root -p=*** -f=/tmp/binlog.log -t=flashback.tbevent 52 -oh=192.168.9.244 -oP=3310 -u=root -op=*** 53 -a=1 54 \033[0m 55 ‘‘‘ 56 57 class flashback: 58 def __init__(self): 59 self.host=‘‘ 60 self.user=‘‘ 61 self.password=‘‘ 62 self.port=‘3306‘ 63 self.fpath=‘‘ 64 self.tbevent=‘‘ 65 66 self.on_host=‘‘ 67 self.on_user=‘‘ 68 self.on_password=‘‘ 69 self.on_port=‘3306‘ 70 71 self.action=0 # 0 just analyse the binlog file ,and store sql in table;1 after execute self.dotype=0, execute the undo_sql in the table 72 73 self._get_db() # 从输入参数获取连接数据库的相关参数值 74 75 # 连接数据库,该数据库是用来存储binlog文件分析后的内容 76 logging.info(‘assign values to parameters is done:host={},user={},password=***,port={},fpath={},tbevent={}‘.format(self.host,self.user,self.port,self.fpath,self.tbevent)) 77 self.mysqlconn = pymysql.connect(host=self.host, user=self.user, password=self.password, port=self.port,charset=‘utf8‘) 78 self.cur = self.mysqlconn.cursor(cursor=DictCursor) 79 logging.info(‘MySQL which userd to store binlog event connection is ok‘) 80 81 # 连接数据库,该数据库的表结构必须跟binlogfile基于对数据库表结构一致 82 # 该数据库用于提供 binlog file 文件中涉及到表结构分析 83 logging.info(‘assign values to online mysql parameters is done:host={},user={},password=***,port={}‘.format(self.on_host, self.on_user, self.on_port)) 84 self.on_mysqlconn = pymysql.connect(host=self.on_host, user=self.on_user, password=self.on_password, port=self.on_port,charset=‘utf8‘) 85 self.on_cur = self.on_mysqlconn.cursor(cursor=DictCursor) 86 logging.info(‘MySQL which userd to analyse online table schema connection is ok‘) 87 88 logging.info(‘\033[33mMySQL connection is ok\033[0m‘) 89 90 self.dml_sql=‘‘ 91 self.undo_sql=‘‘ 92 93 self.tbfield_where = [] 94 self.tbfield_set = [] 95 96 self.begin_time=‘‘ 97 self.db_name=‘‘ 98 self.tb_name=‘‘ 99 self.end_time=‘‘ 100 self.end_pos=‘‘ 101 self.sqltype=0 102 103 #_get_db用于获取执行命令的输入参数 104 def _get_db(self): 105 logging.info(‘begin to assign values to parameters‘) 106 if len(sys.argv) == 1: 107 print(usage) 108 sys.exit(1) 109 elif sys.argv[1] == ‘--help‘: 110 print(usage) 111 sys.exit() 112 elif len(sys.argv) > 2: 113 for i in sys.argv[1:]: 114 _argv = i.split(‘=‘) 115 if _argv[0] == ‘-h‘: 116 self.host = _argv[1] 117 elif _argv[0] == ‘-u‘: 118 self.user = _argv[1] 119 elif _argv[0] == ‘-P‘: 120 self.port = int(_argv[1]) 121 elif _argv[0] == ‘-f‘: 122 self.fpath = _argv[1] 123 elif _argv[0] == ‘-t‘: 124 self.tbevent = _argv[1] 125 elif _argv[0] == ‘-p‘: 126 self.password = _argv[1] 127 128 elif _argv[0] == ‘-oh‘: 129 self.on_host = _argv[1] 130 elif _argv[0] == ‘-ou‘: 131 self.on_user = _argv[1] 132 elif _argv[0] == ‘-oP‘: 133 self.on_port = int(_argv[1]) 134 elif _argv[0] == ‘-op‘: 135 self.on_password = _argv[1] 136 137 elif _argv[0] == ‘-a‘: 138 self.action = _argv[1] 139 140 else: 141 print(usage) 142 143 #创建表格,用于存储分析后的BINLOG内容 144 def create_tab(self): 145 logging.info(‘creating table {} to store binlog event‘.format(self.tbevent)) 146 create_tb_sql =‘‘‘ 147 CREATE TABLE IF NOT EXISTS {}( 148 auto_id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, 149 binlog_name VARCHAR(100) NOT NULL COMMENT ‘the binlog file path and name‘, 150 dml_start_time DATETIME NOT NULL COMMENT ‘when to start this transaction ‘, 151 dml_end_time DATETIME NOT NULL COMMENT ‘when to finish this transaction ‘, 152 end_log_pos BIGINT NOT NULL COMMENT ‘the log position for finish this transaction‘, 153 db_name VARCHAR(100) NOT NULL COMMENT ‘which database happened this transaction ‘, 154 table_name VARCHAR(200) NOT NULL COMMENT ‘which table happened this transaction ‘, 155 sqltype INT NOT NULL COMMENT ‘1 is insert,2 is update,3 is delete‘, 156 dml_sql LONGTEXT NULL COMMENT ‘what sql excuted‘, 157 undo_sql LONGTEXT NULL COMMENT ‘rollback sql, this sql used for flashback‘, 158 PRIMARY KEY (auto_id), 159 INDEX sqltype(sqltype), 160 INDEX dml_start_time (dml_start_time), 161 INDEX dml_end_time (dml_end_time), 162 INDEX end_log_pos (end_log_pos), 163 INDEX db_name (db_name), 164 INDEX table_name (table_name) 165 ) 166 COLLATE=‘utf8_general_ci‘ ENGINE=InnoDB;