开启binlog

这是一个mysql配置文件示例

# 开启二进制日志
log-bin = mysql-bin
# 日志格式(mixed, statement, row)
binlog_format = mixed
# 设置过期时间
expire_logs_days = 30
# server id必须唯一
server-id = 1

查看日志命令

-- 列出二进制日志
show master logs;

-- 具体查看某个日志事件
show binlog events in 'mysql-bin.000003'

show binglog events

show binlog events [IN 'log_name'] [FROM pos] [LIMIT [offset,] row_count];

选项解析:

  • IN ‘log_name’ 指定要查询的binlog文件名(不指定就是第一个binlog文件)
  • FROM pos 指定从哪个pos起始点开始查起(不指定就是从整个文件首个pos点开始算)
  • LIMIT [offset,] 偏移量(不指定就是0)
  • row_count 查询总条数(不指定就是所有行)

启动一个测试用的Docker

docker run --name test-mysql -d \
    -v /home/fayfox/mysql/conf:/etc/mysql/mysql.conf.d/:ro \
    -v /home/fayfox/mysql/data:/var/lib/mysql \
    -e MYSQL_ROOT_PASSWORD=123456 \
    mysql

模拟数据

构建测试库

-- 建库
create database binlogtest;

-- 使用库
use binlogtest;

-- 建表
CREATE TABLE `test` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `title` varchar(255) NOT NULL DEFAULT '',
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- 初始测试数据
INSERT INTO `test`(`title`) VALUES ('a'), ('b'), ('c');

备份库

mysqldump -uroot -p -F binlogtest > ./bak.sql

-F 会在备份前先flush logs

编辑数据

UPDATE `test` SET `title` = 'dd' WHERE `id` = 3;
INSERT INTO `test`(`title`) VALUES ('e');

删表(模拟异常操作)

DROP TABLE `test`;

进行恢复

刷新日志索引

flush logs;

避免当前日志文件继续写入,使问题复杂化

导入之前的备份

利用mysql命令导入

mysql -uroot -p -D binlogtest < bak.sql

进入mysql客户端后用source命令导入

source /var/lib/mysql/bak.sql

查找问题语句位置

利用show binlog events查看

show binlog events in 'binlog.000003';

+---------------+-----+----------------+-----------+-------------+----------------------------------------------------------------------------+
| Log_name      | Pos | Event_type     | Server_id | End_log_pos | Info                                                                       |
+---------------+-----+----------------+-----------+-------------+----------------------------------------------------------------------------+
| binlog.000003 | 696 | Write_rows     |         1 |         743 | table_id: 66 flags: STMT_END_F                                             |
| binlog.000003 | 743 | Xid            |         1 |         774 | COMMIT /* xid=76 */                                                        |
| binlog.000003 | 774 | Anonymous_Gtid |         1 |         847 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS'                                       |
| binlog.000003 | 847 | Query          |         1 |         988 | use `binlogtest`; DROP TABLE `test` /* generated by server */ /* xid=78 */ |
| binlog.000003 | 988 | Rotate         |         1 |        1032 | binlog.000004;pos=4                                                        |
+---------------+-----+----------------+-----------+-------------+----------------------------------------------------------------------------+
15 rows in set (0.00 sec)

可以看到,DROP语句从847位置开始

利用mysqlbinlog命令查看

mysqlbinlog binlog.000003

# at 774
#180717 14:59:38 server id 1  end_log_pos 847 CRC32 0x9fbb510b     Anonymous_GTID    last_committed=2    sequence_number=3    rbr_only=no    original_committed_timestamp=1531839578681339    immediate_commit_timestamp=1531839578681339    transaction_length=214
# original_commit_timestamp=1531839578681339 (2018-07-17 14:59:38.681339 UTC)
# immediate_commit_timestamp=1531839578681339 (2018-07-17 14:59:38.681339 UTC)
/*!80001 SET @@session.original_commit_timestamp=1531839578681339*//*!*/;
SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/;
# at 847
#180717 14:59:38 server id 1  end_log_pos 988 CRC32 0x60ea3242     Query    thread_id=8    exec_time=0    error_code=0    Xid = 78
use `binlogtest`/*!*/;
SET TIMESTAMP=1531839578/*!*/;
DROP TABLE `test` /* generated by server */
/*!*/;

同样可以看到,DROP语句从847位置开始

执行恢复

mysqlbinlog --stop-position=847 ./binlog.000003 | mysql -uroot -p -D binlogtest