add options: start-datetime, stop-datetime

This commit is contained in:
danfengcao 2016-12-13 20:49:26 +08:00
parent 315621d533
commit 2283302a4e
4 changed files with 90 additions and 69 deletions

View File

@ -6,7 +6,7 @@ binlog2sql
用途 用途
=========== ===========
* 数据回滚 * 数据快速回滚(闪回)
* 主从切换后数据不一致的修复 * 主从切换后数据不一致的修复
* 从binlog生成标准SQL带来的衍生功能 * 从binlog生成标准SQL带来的衍生功能
@ -24,8 +24,8 @@ binlog2sql
============== ==============
``` ```
git clone https://github.com/danfengcao/binlog2sql.git shell> git clone https://github.com/danfengcao/binlog2sql.git
pip install -r requirements.txt shell> pip install -r requirements.txt
``` ```
使用 使用
@ -36,7 +36,7 @@ pip install -r requirements.txt
[mysqld] [mysqld]
server-id = 1 server-id = 1
log_bin = /var/log/mysql/mysql-bin.log log_bin = /var/log/mysql/mysql-bin.log
max_binlog_size = 1000M max_binlog_size = 100M
binlog-format = row binlog-format = row
###基本用法 ###基本用法
@ -44,11 +44,9 @@ pip install -r requirements.txt
**解析出标准SQL** **解析出标准SQL**
```bash ```bash
$ python binlog2sql.py -h127.0.0.1 -P3306 -uadmin -p'admin' -dtest -t test3 test4 --start-file='mysql-bin.000002' shell> python binlog2sql.py -h127.0.0.1 -P3306 -uadmin -p'admin' -dtest -t test3 test4 --start-file='mysql-bin.000002'
输出: 输出:
INSERT INTO `test`.`test4`(`addtime`, `data`, `id`) VALUES ('2016-12-10 13:03:10', 'test', 1); #start 185 end 351
INSERT INTO `test`.`test3`(`addtime`, `data`, `id`) VALUES ('2016-12-10 13:03:22', '中文', 3); #start 378 end 543
INSERT INTO `test`.`test3`(`addtime`, `data`, `id`) VALUES ('2016-12-10 13:03:38', 'english', 4); #start 570 end 736 INSERT INTO `test`.`test3`(`addtime`, `data`, `id`) VALUES ('2016-12-10 13:03:38', 'english', 4); #start 570 end 736
UPDATE `test`.`test3` SET `addtime`='2016-12-10 12:00:00', `data`='中文', `id`=3 WHERE `addtime`='2016-12-10 13:03:22' AND `data`='中文' AND `id`=3 LIMIT 1; #start 763 end 954 UPDATE `test`.`test3` SET `addtime`='2016-12-10 12:00:00', `data`='中文', `id`=3 WHERE `addtime`='2016-12-10 13:03:22' AND `data`='中文' AND `id`=3 LIMIT 1; #start 763 end 954
DELETE FROM `test`.`test3` WHERE `addtime`='2016-12-10 13:03:38' AND `data`='english' AND `id`=4 LIMIT 1; #start 981 end 1147 DELETE FROM `test`.`test3` WHERE `addtime`='2016-12-10 13:03:38' AND `data`='english' AND `id`=4 LIMIT 1; #start 981 end 1147
@ -57,7 +55,7 @@ DELETE FROM `test`.`test3` WHERE `addtime`='2016-12-10 13:03:38' AND `data`='eng
**解析出回滚SQL** **解析出回滚SQL**
```bash ```bash
python binlog2sql.py --flashback -h127.0.0.1 -P3306 -uadmin -p'admin' -dtest -ttest3 --start-file='mysql-bin.000002' --start-pos=763 --end-pos=1147 shell> python binlog2sql.py --flashback -h127.0.0.1 -P3306 -uadmin -p'admin' -dtest -ttest3 --start-file='mysql-bin.000002' --start-pos=763 --end-pos=1147
输出: 输出:
INSERT INTO `test`.`test3`(`addtime`, `data`, `id`) VALUES ('2016-12-10 13:03:38', 'english', 4); #start 981 end 1147 INSERT INTO `test`.`test3`(`addtime`, `data`, `id`) VALUES ('2016-12-10 13:03:38', 'english', 4); #start 981 end 1147
@ -106,15 +104,15 @@ mysql> select * from tbl;
+----+--------+---------------------+ +----+--------+---------------------+
| 1 | 小赵 | 2016-12-10 00:04:33 | | 1 | 小赵 | 2016-12-10 00:04:33 |
| 2 | 小钱 | 2016-12-10 00:04:48 | | 2 | 小钱 | 2016-12-10 00:04:48 |
| 3 | 小孙 | 2016-12-10 00:04:51 | | 3 | 小孙 | 2016-12-13 20:25:00 |
| 4 | 小李 | 2016-12-10 00:04:56 | | 4 | 小李 | 2016-12-12 00:00:00 |
+----+--------+---------------------+ +----+--------+---------------------+
4 rows in set (0.00 sec) 4 rows in set (0.00 sec)
mysql> delete from tbl; mysql> delete from tbl;
Query OK, 4 rows affected (0.00 sec) Query OK, 4 rows affected (0.00 sec)
tbl表被清空 20:28时tbl表误操作被清空
mysql> select * from tbl; mysql> select * from tbl;
Empty set (0.00 sec) Empty set (0.00 sec)
``` ```
@ -124,41 +122,44 @@ Empty set (0.00 sec)
1. 登录mysql查看目前的binlog文件 1. 登录mysql查看目前的binlog文件
```bash ```bash
mysql> show master logs; mysql> show master status;
+------------------+-----------+ +------------------+-----------+
| Log_name | File_size | | Log_name | File_size |
+------------------+-----------+ +------------------+-----------+
| mysql-bin.000046 | 12262268 | | mysql-bin.000051 | 967 |
| mysql-bin.000047 | 3583 | | mysql-bin.000052 | 965 |
+------------------+-----------+ +------------------+-----------+
``` ```
2. 最新的binlog文件是mysql-bin.000047我们再定位误操作SQL的binlog位置 2. 最新的binlog文件是mysql-bin.000052我们再定位误操作SQL的binlog位置。误操作人只能知道大致的误操作时间我们根据大致时间过滤数据。
```bash ```bash
$ python binlog2sql/binlog2sql.py -h127.0.0.1 -P3306 -uadmin -p'admin' -dtest -ttbl --start-file='mysql-bin.000047' shell> python binlog2sql/binlog2sql.py -h127.0.0.1 -P3306 -uadmin -p'admin' -dtest -ttbl --start-file='mysql-bin.000052' --start-datetime='2016-12-13 20:25:00' --stop-datetime='2016-12-13 20:30:00'
输出: 输出:
DELETE FROM `test`.`tbl` WHERE `addtime`='2016-12-10 00:04:33' AND `id`=1 AND `name`='小赵' LIMIT 1; #start 3346 end 3556 INSERT INTO `test`.`tbl`(`addtime`, `id`, `name`) VALUES ('2016-12-13 20:25:00', 3, '小孙'); #start 4 end 290 time 2016-12-13 20:25:46
DELETE FROM `test`.`tbl` WHERE `addtime`='2016-12-10 00:04:48' AND `id`=2 AND `name`='小钱' LIMIT 1; #start 3346 end 3556 INSERT INTO `test`.`tbl`(`addtime`, `id`, `name`) VALUES ('2016-12-13 20:26:00', 4, '小李'); #start 317 end 487 time 2016-12-13 20:26:26
DELETE FROM `test`.`tbl` WHERE `addtime`='2016-12-10 00:04:51' AND `id`=3 AND `name`='小孙' LIMIT 1; #start 3346 end 3556 UPDATE `test`.`tbl` SET `addtime`='2016-12-12 00:00:00', `id`=4, `name`='小李' WHERE `addtime`='2016-12-13 20:26:00' AND `id`=4 AND `name`='小李' LIMIT 1; #start 514 end 701 time 2016-12-13 20:27:07
DELETE FROM `test`.`tbl` WHERE `addtime`='2016-12-10 00:04:56' AND `id`=4 AND `name`='小李' LIMIT 1; #start 3346 end 3556 DELETE FROM `test`.`tbl` WHERE `addtime`='2016-12-10 00:04:33' AND `id`=1 AND `name`='小赵' LIMIT 1; #start 728 end 938 time 2016-12-13 20:28:05
DELETE FROM `test`.`tbl` WHERE `addtime`='2016-12-10 00:04:48' AND `id`=2 AND `name`='小钱' LIMIT 1; #start 728 end 938 time 2016-12-13 20:28:05
DELETE FROM `test`.`tbl` WHERE `addtime`='2016-12-13 20:25:00' AND `id`=3 AND `name`='小孙' LIMIT 1; #start 728 end 938 time 2016-12-13 20:28:05
DELETE FROM `test`.`tbl` WHERE `addtime`='2016-12-12 00:00:00' AND `id`=4 AND `name`='小李' LIMIT 1; #start 728 end 938 time 2016-12-13 20:28:05
``` ```
3. 生成回滚sql并检查回滚sql是否正确 3. 我们得到了误操作sql的准确位置在728-938之间再根据位置进一步过滤使用flashback模式生成回滚sql检查回滚sql是否正确
```bash ```bash
$ python binlog2sql/binlog2sql.py -h127.0.0.1 -P3306 -uadmin -p'admin' -dtest -ttbl --start-file='mysql-bin.000047' --start-pos=3346 --end-pos=3556 -B shell> python binlog2sql/binlog2sql.py -h127.0.0.1 -P3306 -uadmin -p'admin' -dtest -ttbl --start-file='mysql-bin.000052' --start-pos=3346 --end-pos=3556 -B
输出: 输出:
INSERT INTO `test`.`tbl`(`addtime`, `id`, `name`) VALUES ('2016-12-10 00:04:56', 4, '小李'); #start 3346 end 3556 INSERT INTO `test`.`tbl`(`addtime`, `id`, `name`) VALUES ('2016-12-12 00:00:00', 4, '小李'); #start 728 end 938 time 2016-12-13 20:28:05
INSERT INTO `test`.`tbl`(`addtime`, `id`, `name`) VALUES ('2016-12-10 00:04:51', 3, '小孙'); #start 3346 end 3556 INSERT INTO `test`.`tbl`(`addtime`, `id`, `name`) VALUES ('2016-12-13 20:25:00', 3, '小孙'); #start 728 end 938 time 2016-12-13 20:28:05
INSERT INTO `test`.`tbl`(`addtime`, `id`, `name`) VALUES ('2016-12-10 00:04:48', 2, '小钱'); #start 3346 end 3556 INSERT INTO `test`.`tbl`(`addtime`, `id`, `name`) VALUES ('2016-12-10 00:04:48', 2, '小钱'); #start 728 end 938 time 2016-12-13 20:28:05
INSERT INTO `test`.`tbl`(`addtime`, `id`, `name`) VALUES ('2016-12-10 00:04:33', 1, '小赵'); #start 3346 end 3556 INSERT INTO `test`.`tbl`(`addtime`, `id`, `name`) VALUES ('2016-12-10 00:04:33', 1, '小赵'); #start 728 end 938 time 2016-12-13 20:28:05
``` ```
3. 确认回滚sql正确执行回滚语句。登录mysql确认数据回滚成功。 3. 确认回滚sql正确执行回滚语句。登录mysql确认数据回滚成功。
```bash ```bash
$ python binlog2sql.py -h127.0.0.1 -P3306 -uadmin -p'admin' -dtest -ttbl --start-file='mysql-bin.000047' --start-pos=3346 --end-pos=3556 -B | mysql -h127.0.0.1 -P3306 -uadmin -p'admin' shell> python binlog2sql.py -h127.0.0.1 -P3306 -uadmin -p'admin' -dtest -ttbl --start-file='mysql-bin.000052' --start-pos=3346 --end-pos=3556 -B | mysql -h127.0.0.1 -P3306 -uadmin -p'admin'
mysql> select * from tbl; mysql> select * from tbl;
+----+--------+---------------------+ +----+--------+---------------------+
@ -166,8 +167,8 @@ mysql> select * from tbl;
+----+--------+---------------------+ +----+--------+---------------------+
| 1 | 小赵 | 2016-12-10 00:04:33 | | 1 | 小赵 | 2016-12-10 00:04:33 |
| 2 | 小钱 | 2016-12-10 00:04:48 | | 2 | 小钱 | 2016-12-10 00:04:48 |
| 3 | 小孙 | 2016-12-10 00:04:51 | | 3 | 小孙 | 2016-12-13 20:25:00 |
| 4 | 小李 | 2016-12-10 00:04:56 | | 4 | 小李 | 2016-12-12 00:00:00 |
+----+--------+---------------------+ +----+--------+---------------------+
``` ```

View File

@ -1,7 +1,7 @@
#!/usr/bin/python #!/usr/bin/python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import os import os, datetime
import pymysql import pymysql
from pymysqlreplication import BinLogStreamReader from pymysqlreplication import BinLogStreamReader
from pymysqlreplication.row_event import ( from pymysqlreplication.row_event import (
@ -14,8 +14,8 @@ from binlog2sql_util import command_line_args, concat_sql_from_binlogevent, crea
class Binlog2sql(object): class Binlog2sql(object):
def __init__(self, connectionSettings, startFile=None, startPos=None, endFile=None, def __init__(self, connectionSettings, startFile=None, startPos=None, endFile=None, endPos=None, startTime=None,
endPos=None, only_schemas=None, only_tables=None, popPk=False, flashback=False, stopnever=False): stopTime=None, only_schemas=None, only_tables=None, popPk=False, flashback=False, stopnever=False):
''' '''
connectionSettings: {'host': 127.0.0.1, 'port': 3306, 'user': slave, 'passwd': slave} connectionSettings: {'host': 127.0.0.1, 'port': 3306, 'user': slave, 'passwd': slave}
''' '''
@ -24,9 +24,11 @@ class Binlog2sql(object):
self.connectionSettings = connectionSettings self.connectionSettings = connectionSettings
self.startFile = startFile self.startFile = startFile
self.startPos = startPos if startPos else 4 self.startPos = startPos if startPos else 4 # use binlog v4
self.endFile = endFile if endFile else startFile self.endFile = endFile if endFile else startFile
self.endPos = endPos self.endPos = endPos
self.startTime = datetime.datetime.strptime(startTime, "%Y-%m-%d %H:%M:%S") if startTime else datetime.datetime.strptime('1970-01-01 00:00:00', "%Y-%m-%d %H:%M:%S")
self.stopTime = datetime.datetime.strptime(stopTime, "%Y-%m-%d %H:%M:%S") if stopTime else datetime.datetime.strptime('2999-12-31 00:00:00', "%Y-%m-%d %H:%M:%S")
self.only_schemas = only_schemas if only_schemas else None self.only_schemas = only_schemas if only_schemas else None
self.only_tables = only_tables if only_tables else None self.only_tables = only_tables if only_tables else None
@ -69,9 +71,9 @@ class Binlog2sql(object):
if not self.stopnever: if not self.stopnever:
if (stream.log_file == self.endFile and stream.log_pos == self.endPos) or (stream.log_file == self.eofFile and stream.log_pos == self.eofPos): if (stream.log_file == self.endFile and stream.log_pos == self.endPos) or (stream.log_file == self.eofFile and stream.log_pos == self.eofPos):
flagLastEvent = True flagLastEvent = True
elif stream.log_file not in self.binlogList: elif datetime.datetime.fromtimestamp(binlogevent.__dict__['timestamp']) < self.startTime:
break continue
elif (self.endPos and stream.log_file == self.endFile and stream.log_pos > self.endPos) or (stream.log_file == self.eofFile and stream.log_pos > self.eofPos): elif (stream.log_file not in self.binlogList) or (self.endPos and stream.log_file == self.endFile and stream.log_pos > self.endPos) or (stream.log_file == self.eofFile and stream.log_pos > self.eofPos) or (datetime.datetime.fromtimestamp(binlogevent.__dict__['timestamp']) >= self.stopTime):
break break
# else: # else:
# raise ValueError('unknown binlog file or position') # raise ValueError('unknown binlog file or position')
@ -117,5 +119,6 @@ if __name__ == '__main__':
connectionSettings = {'host':args.host, 'port':args.port, 'user':args.user, 'passwd':args.password} connectionSettings = {'host':args.host, 'port':args.port, 'user':args.user, 'passwd':args.password}
binlog2sql = Binlog2sql(connectionSettings=connectionSettings, startFile=args.startFile, binlog2sql = Binlog2sql(connectionSettings=connectionSettings, startFile=args.startFile,
startPos=args.startPos, endFile=args.endFile, endPos=args.endPos, startPos=args.startPos, endFile=args.endFile, endPos=args.endPos,
only_schemas=args.databases, only_tables=args.tables, popPk=args.popPk, flashback=args.flashback, stopnever=args.stopnever) startTime=args.startTime, stopTime=args.stopTime, only_schemas=args.databases,
only_tables=args.tables, popPk=args.popPk, flashback=args.flashback, stopnever=args.stopnever)
binlog2sql.process_binlog() binlog2sql.process_binlog()

View File

@ -1,7 +1,7 @@
#!/usr/bin/python #!/usr/bin/python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import os, sys, argparse import os, sys, argparse, datetime
import pymysql import pymysql
from pymysqlreplication import BinLogStreamReader from pymysqlreplication import BinLogStreamReader
from pymysqlreplication.row_event import ( from pymysqlreplication.row_event import (
@ -11,6 +11,14 @@ from pymysqlreplication.row_event import (
) )
from pymysqlreplication.event import QueryEvent, RotateEvent, FormatDescriptionEvent from pymysqlreplication.event import QueryEvent, RotateEvent, FormatDescriptionEvent
def is_valid_datetime(string):
try:
datetime.datetime.strptime(string, "%Y-%m-%d %H:%M:%S")
return True
except:
return False
def create_unique_file(filename): def create_unique_file(filename):
version = 0 version = 0
resultFile = filename resultFile = filename
@ -40,11 +48,15 @@ def command_line_parser():
range.add_argument('--start-file', dest='startFile', type=str, range.add_argument('--start-file', dest='startFile', type=str,
help='Start binlog file to be parsed') help='Start binlog file to be parsed')
range.add_argument('--start-pos', dest='startPos', type=int, range.add_argument('--start-pos', dest='startPos', type=int,
help='start position of start binlog file', default=4) help='start position of the --start-file', default=4)
range.add_argument('--end-file', dest='endFile', type=str, range.add_argument('--end-file', dest='endFile', type=str,
help="End binlog file to be parsed. default: '--start-file'", default='') help="End binlog file to be parsed. default: '--start-file'", default='')
range.add_argument('--end-pos', dest='endPos', type=int, range.add_argument('--end-pos', dest='endPos', type=int,
help="stop position of end binlog file. default: end position of '--end-file'", default=0) help="stop position of --end-file. default: end position of '--end-file'", default=0)
range.add_argument('--start-datetime', dest='startTime', type=str,
help="Start reading the binlog at first event having a datetime equal or posterior to the argument; the argument must be a date and time in the local time zone, in any format accepted by the MySQL server for DATETIME and TIMESTAMP types, for example: 2004-12-25 11:25:56 (you should probably use quotes for your shell to set it properly).", default='')
range.add_argument('--stop-datetime', dest='stopTime', type=str,
help="Stop reading the binlog at first event having a datetime equal or posterior to the argument; the argument must be a date and time in the local time zone, in any format accepted by the MySQL server for DATETIME and TIMESTAMP types, for example: 2004-12-25 11:25:56 (you should probably use quotes for your shell to set it properly).", default='')
parser.add_argument('--stop-never', dest='stopnever', action='store_true', parser.add_argument('--stop-never', dest='stopnever', action='store_true',
help='Wait for more data from the server. default: stop replicate at the last binlog when you start binlog2sql', default=False) help='Wait for more data from the server. default: stop replicate at the last binlog when you start binlog2sql', default=False)
@ -73,6 +85,8 @@ def command_line_args():
raise ValueError('only one of flashback or stop-never can be True') raise ValueError('only one of flashback or stop-never can be True')
if args.flashback and args.popPk: if args.flashback and args.popPk:
raise ValueError('only one of flashback or popPk can be True') raise ValueError('only one of flashback or popPk can be True')
if (args.startTime and not is_valid_datetime(args.startTime)) or (args.stopTime and not is_valid_datetime(args.stopTime)):
raise ValueError('Incorrect date and time argument')
return args return args
@ -147,5 +161,5 @@ def concat_sql_from_binlogevent(cursor, binlogevent, row=None, eStartPos=None, f
binlogevent.schema, fix_object(binlogevent.query) binlogevent.schema, fix_object(binlogevent.query)
) )
if type(binlogevent) in (WriteRowsEvent, UpdateRowsEvent, DeleteRowsEvent): if type(binlogevent) in (WriteRowsEvent, UpdateRowsEvent, DeleteRowsEvent):
sql += ' #start %s end %s' % (eStartPos, binlogevent.packet.log_pos) sql += ' #start %s end %s time %s' % (eStartPos, binlogevent.packet.log_pos, datetime.datetime.fromtimestamp(binlogevent.__dict__['timestamp']))
return sql return sql

View File

@ -28,7 +28,7 @@ pip install -r requirements.txt
然后我们就可以生成回滚SQL了。 然后我们就可以生成回滚SQL了。
**背景**误删了test库tbl表整张表的数据需要紧急回滚。 **背景**小明在20点多时误删了test库tbl表整张表的数据需要紧急回滚。
```bash ```bash
test库tbl表原有数据 test库tbl表原有数据
@ -38,15 +38,15 @@ mysql> select * from tbl;
+----+--------+---------------------+ +----+--------+---------------------+
| 1 | 小赵 | 2016-12-10 00:04:33 | | 1 | 小赵 | 2016-12-10 00:04:33 |
| 2 | 小钱 | 2016-12-10 00:04:48 | | 2 | 小钱 | 2016-12-10 00:04:48 |
| 3 | 小孙 | 2016-12-10 00:04:51 | | 3 | 小孙 | 2016-12-13 20:25:00 |
| 4 | 小李 | 2016-12-10 00:04:56 | | 4 | 小李 | 2016-12-12 00:00:00 |
+----+--------+---------------------+ +----+--------+---------------------+
4 rows in set (0.00 sec) 4 rows in set (0.00 sec)
mysql> delete from tbl; mysql> delete from tbl;
Query OK, 4 rows affected (0.00 sec) Query OK, 4 rows affected (0.00 sec)
tbl表被清空 20:28时tbl表误操作被清空
mysql> select * from tbl; mysql> select * from tbl;
Empty set (0.00 sec) Empty set (0.00 sec)
``` ```
@ -56,41 +56,44 @@ Empty set (0.00 sec)
1. 登录mysql查看目前的binlog文件 1. 登录mysql查看目前的binlog文件
```bash ```bash
mysql> show master logs; mysql> show master status;
+------------------+-----------+ +------------------+-----------+
| Log_name | File_size | | Log_name | File_size |
+------------------+-----------+ +------------------+-----------+
| mysql-bin.000046 | 12262268 | | mysql-bin.000051 | 967 |
| mysql-bin.000047 | 3583 | | mysql-bin.000052 | 965 |
+------------------+-----------+ +------------------+-----------+
``` ```
2. 最新的binlog文件是mysql-bin.000047我们再定位误操作SQL的binlog位置 2. 最新的binlog文件是mysql-bin.000052我们再定位误操作SQL的binlog位置。误操作人只能知道大致的误操作时间我们根据大致时间过滤数据。
```bash ```bash
$ python binlog2sql/binlog2sql.py -h127.0.0.1 -P3306 -uadmin -p'admin' -dtest -ttbl --start-file='mysql-bin.000047' shell> python binlog2sql/binlog2sql.py -h127.0.0.1 -P3306 -uadmin -p'admin' -dtest -ttbl --start-file='mysql-bin.000052' --start-datetime='2016-12-13 20:25:00' --stop-datetime='2016-12-13 20:30:00'
输出: 输出:
DELETE FROM `test`.`tbl` WHERE `addtime`='2016-12-10 00:04:33' AND `id`=1 AND `name`='小赵' LIMIT 1; #start 3346 end 3556 INSERT INTO `test`.`tbl`(`addtime`, `id`, `name`) VALUES ('2016-12-13 20:25:00', 3, '小孙'); #start 4 end 290 time 2016-12-13 20:25:46
DELETE FROM `test`.`tbl` WHERE `addtime`='2016-12-10 00:04:48' AND `id`=2 AND `name`='小钱' LIMIT 1; #start 3346 end 3556 INSERT INTO `test`.`tbl`(`addtime`, `id`, `name`) VALUES ('2016-12-13 20:26:00', 4, '小李'); #start 317 end 487 time 2016-12-13 20:26:26
DELETE FROM `test`.`tbl` WHERE `addtime`='2016-12-10 00:04:51' AND `id`=3 AND `name`='小孙' LIMIT 1; #start 3346 end 3556 UPDATE `test`.`tbl` SET `addtime`='2016-12-12 00:00:00', `id`=4, `name`='小李' WHERE `addtime`='2016-12-13 20:26:00' AND `id`=4 AND `name`='小李' LIMIT 1; #start 514 end 701 time 2016-12-13 20:27:07
DELETE FROM `test`.`tbl` WHERE `addtime`='2016-12-10 00:04:56' AND `id`=4 AND `name`='小李' LIMIT 1; #start 3346 end 3556 DELETE FROM `test`.`tbl` WHERE `addtime`='2016-12-10 00:04:33' AND `id`=1 AND `name`='小赵' LIMIT 1; #start 728 end 938 time 2016-12-13 20:28:05
DELETE FROM `test`.`tbl` WHERE `addtime`='2016-12-10 00:04:48' AND `id`=2 AND `name`='小钱' LIMIT 1; #start 728 end 938 time 2016-12-13 20:28:05
DELETE FROM `test`.`tbl` WHERE `addtime`='2016-12-13 20:25:00' AND `id`=3 AND `name`='小孙' LIMIT 1; #start 728 end 938 time 2016-12-13 20:28:05
DELETE FROM `test`.`tbl` WHERE `addtime`='2016-12-12 00:00:00' AND `id`=4 AND `name`='小李' LIMIT 1; #start 728 end 938 time 2016-12-13 20:28:05
``` ```
3. 生成回滚sql并检查回滚sql是否正确 3. 我们得到了误操作sql的准确位置在728-938之间再根据位置进一步过滤使用flashback模式生成回滚sql检查回滚sql是否正确
```bash ```bash
$ python binlog2sql/binlog2sql.py -h127.0.0.1 -P3306 -uadmin -p'admin' -dtest -ttbl --start-file='mysql-bin.000047' --start-pos=3346 --end-pos=3556 -B shell> python binlog2sql/binlog2sql.py -h127.0.0.1 -P3306 -uadmin -p'admin' -dtest -ttbl --start-file='mysql-bin.000052' --start-pos=3346 --end-pos=3556 -B
输出: 输出:
INSERT INTO `test`.`tbl`(`addtime`, `id`, `name`) VALUES ('2016-12-10 00:04:56', 4, '小李'); #start 3346 end 3556 INSERT INTO `test`.`tbl`(`addtime`, `id`, `name`) VALUES ('2016-12-12 00:00:00', 4, '小李'); #start 728 end 938 time 2016-12-13 20:28:05
INSERT INTO `test`.`tbl`(`addtime`, `id`, `name`) VALUES ('2016-12-10 00:04:51', 3, '小孙'); #start 3346 end 3556 INSERT INTO `test`.`tbl`(`addtime`, `id`, `name`) VALUES ('2016-12-13 20:25:00', 3, '小孙'); #start 728 end 938 time 2016-12-13 20:28:05
INSERT INTO `test`.`tbl`(`addtime`, `id`, `name`) VALUES ('2016-12-10 00:04:48', 2, '小钱'); #start 3346 end 3556 INSERT INTO `test`.`tbl`(`addtime`, `id`, `name`) VALUES ('2016-12-10 00:04:48', 2, '小钱'); #start 728 end 938 time 2016-12-13 20:28:05
INSERT INTO `test`.`tbl`(`addtime`, `id`, `name`) VALUES ('2016-12-10 00:04:33', 1, '小赵'); #start 3346 end 3556 INSERT INTO `test`.`tbl`(`addtime`, `id`, `name`) VALUES ('2016-12-10 00:04:33', 1, '小赵'); #start 728 end 938 time 2016-12-13 20:28:05
``` ```
4. 确认回滚sql正确执行回滚语句。登录mysql确认数据回滚成功。 3. 确认回滚sql正确执行回滚语句。登录mysql确认数据回滚成功。
```bash ```bash
$ python binlog2sql.py -h127.0.0.1 -P3306 -uadmin -p'admin' -dtest -ttbl --start-file='mysql-bin.000047' --start-pos=3346 --end-pos=3556 -B | mysql -h127.0.0.1 -P3306 -uadmin -p'admin' shell> python binlog2sql.py -h127.0.0.1 -P3306 -uadmin -p'admin' -dtest -ttbl --start-file='mysql-bin.000052' --start-pos=3346 --end-pos=3556 -B | mysql -h127.0.0.1 -P3306 -uadmin -p'admin'
mysql> select * from tbl; mysql> select * from tbl;
+----+--------+---------------------+ +----+--------+---------------------+
@ -98,8 +101,8 @@ mysql> select * from tbl;
+----+--------+---------------------+ +----+--------+---------------------+
| 1 | 小赵 | 2016-12-10 00:04:33 | | 1 | 小赵 | 2016-12-10 00:04:33 |
| 2 | 小钱 | 2016-12-10 00:04:48 | | 2 | 小钱 | 2016-12-10 00:04:48 |
| 3 | 小孙 | 2016-12-10 00:04:51 | | 3 | 小孙 | 2016-12-13 20:25:00 |
| 4 | 小李 | 2016-12-10 00:04:56 | | 4 | 小李 | 2016-12-12 00:00:00 |
+----+--------+---------------------+ +----+--------+---------------------+
``` ```