在MySQL中,binlog文件主要用于主从同步二进制数据日志。当主服务器数据发生变更时,会把变动明细持久化到binlog文件中,此时从服务器通过拉取并解析binlog文件,实现数据的同步。正是由于binlog文件中记录了数据变更的信息,因此MySQL的闪回是基于binlog文件来实现的。
如果要在MySQL中实现闪回,则必须要求binlog文件日志格式是 binlog_format=row ,并且 binlog_row_image=full 。通过指定binlog文件的日志格式,就能在binlog中完整记录数据变化的轨迹和具体的操作行为(增删改)的前后差异。
我们可以解析并处理binlog文件中的事件,然后SQL反序遍历。同时对增删改进行反转逆操作,即插入映射成删除、删除映射成插入、更新交换新旧数据区间。最后输出对应数据回滚的binlog文件,将其再次导入mysql,即完成对增删改数据的回滚还原。
下述为操作步骤
create table cs2 ( `id` int(10) unsigned not null auto_increment,
`name` varchar(16) not null,
`sex` enum('m','w') not null default 'm',
`age` tinyint(3) unsigned not null,
primary key (`id`) ) engine=innodb default charset=utf8mb4;
insert into ceshidb.cs2(`name`,`sex`,`age`) values
('cs1','w',21),
('cs2','m',22),
('cs3','w',23),
('cs4','m',24),
('cs5','w',25);
commit;
select * from ceshidb.cs2;
今天上午误操作:
delete from cs2 where id=2;
delete from cs2;
commit; -- 完了。发现弄错了
select * from ceshidb.cs2;开始恢复,生产高峰:
lock tables cs2 read; ----先把表设置为只读,防止cs2表有新的数据变更
show master status; -- mysql-binlog.000026:1959
show binlog events in 'mysql-binlog.000026'; --1725:1959
mysqlbinlog --base64-output=decode-rows -v -v mysql-binlog.000026
mysqlbinlog --base64-output=decode-rows -v -v mysql-binlog.000026 |sed -n '/### DELETE FROM `ceshidb`.`cs2`/,/COMMIT/p' > cs2.txt
cat cs2.txt | sed -n '/###/p' | sed 's/### //g;s/\/\*.*/,/g;s/DELETE FROM/INSERT INTO/g;s/WHERE/SELECT/g;' | sed -r 's/(@4.*),/\1;/g' | sed 's/@[1-9]=//g' > recover_cs2.sql
然后解锁表:
unlock tables;
lock tables cs2 write;
编辑 recover_cs2.sql,在文件最后加上 commit; 或者在导入完成后执行commit; 也可以把 recover_cs2.sql里面的sql复制出来进行执行。
unlock tables;source recover_cs2.sql
root@mysqldb15:47: [ceshidb]> select * from cs2;
+----+------+-----+-----+
| id | name | sex | age |
+----+------+-----+-----+
| 1 | cs1 | w | 21 |
| 2 | cs2 | m | 22 |
| 3 | cs3 | w | 23 |
| 4 | cs4 | m | 24 |
| 5 | cs5 | w | 25 |
+----+------+-----+-----+
5 rows in set (0.00 sec)
欢迎大家提出合理的意见及建议,因个人能力有限,文章中难免有遗漏的地方,望见谅。此文章思路及方案可实施到线上环境,但请先在测试环境进行验证后,再到线上实施。祝大家年薪百万!