刪除誤操作有時會意外出現,如果你有備份表數據的好習慣,那么至少你可以追回備份前的那些數據。如果我們打開了mysql的binlog,那么可以通過它的增量操作日志來恢復數據。怎么打開binlog前篇已有說明(參見windows下打開binlog),這里舉例說明如何通過binlog進行恢復:
1、看下當前的binlog位置,這里稱為位置1:
mysql> show master status; +---------------------+----------+--------------+------------------+-------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set | +---------------------+----------+--------------+------------------+-------------------+ | mysql-binlog.000001 | 529 | | | | +---------------------+----------+--------------+------------------+-------------------+ 1 row in set (0.01 sec)
2、執行DML操作,創建一個測試表,插入2條數據后誤操作刪除了其中一條:
mysql> create table t_test( -> name varchar(50) default null); Query OK, 0 rows affected (0.06 sec) mysql> insert into t_test values('wlf'); Query OK, 1 row affected (0.01 sec) mysql> insert into t_test values('wms'); Query OK, 1 row affected (0.01 sec) mysql> delete from t_test where name = 'wlf'; Query OK, 1 row affected (0.01 sec)
3、再看現在binlog的位置,這里稱為位置2:
mysql> show master status; +---------------------+----------+--------------+------------------+-------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set | +---------------------+----------+--------------+------------------+-------------------+ | mysql-binlog.000001 | 1496 | | | | +---------------------+----------+--------------+------------------+-------------------+ 1 row in set (0.00 sec)
4、我們如果要恢復那條刪除的數據,那么應該知道截至到刪除前的那一刻所在的位置是多少,而這個位置必然位於位置1(即529)和2(即1496)之間:
mysql> show binlog events in 'mysql-binlog.000001' from 529; +---------------------+------+----------------+-----------+-------------+-----------------------------------------------------------------+ | Log_name | Pos | Event_type | Server_id | End_log_pos | Info | +---------------------+------+----------------+-----------+-------------+-----------------------------------------------------------------+ | mysql-binlog.000001 | 529 | Anonymous_Gtid | 1 | 594 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS' | | mysql-binlog.000001 | 594 | Query | 1 | 719 | use `test`; create table t_test( name varchar(50) default null) | | mysql-binlog.000001 | 719 | Anonymous_Gtid | 1 | 784 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS' | | mysql-binlog.000001 | 784 | Query | 1 | 856 | BEGIN | | mysql-binlog.000001 | 856 | Table_map | 1 | 907 | table_id: 109 (test.t_test) | | mysql-binlog.000001 | 907 | Write_rows | 1 | 947 | table_id: 109 flags: STMT_END_F | | mysql-binlog.000001 | 947 | Xid | 1 | 978 | COMMIT /* xid=11 */ | | mysql-binlog.000001 | 978 | Anonymous_Gtid | 1 | 1043 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS' | | mysql-binlog.000001 | 1043 | Query | 1 | 1115 | BEGIN | | mysql-binlog.000001 | 1115 | Table_map | 1 | 1166 | table_id: 109 (test.t_test) | | mysql-binlog.000001 | 1166 | Write_rows | 1 | 1206 | table_id: 109 flags: STMT_END_F | | mysql-binlog.000001 | 1206 | Xid | 1 | 1237 | COMMIT /* xid=12 */ | | mysql-binlog.000001 | 1237 | Anonymous_Gtid | 1 | 1302 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS' | | mysql-binlog.000001 | 1302 | Query | 1 | 1374 | BEGIN | | mysql-binlog.000001 | 1374 | Table_map | 1 | 1425 | table_id: 109 (test.t_test) | | mysql-binlog.000001 | 1425 | Delete_rows | 1 | 1465 | table_id: 109 flags: STMT_END_F | | mysql-binlog.000001 | 1465 | Xid | 1 | 1496 | COMMIT /* xid=13 */ | +---------------------+------+----------------+-----------+-------------+-----------------------------------------------------------------+ 17 rows in set (0.02 sec)
我們看到594到719是建表,719到978是第一條插入語句,978到1237是第二條插入語句,1237到1465是誤操作刪除第一條插入數據的語句。那這會兒我們已經知道增量日志用於恢復刪除操作的截至位置了,很明顯就是1237,那么開始位置呢?執行恢復前,我們確認下目前t_test只有一條數據:
mysql> select * from t_test; +------+ | name | +------+ | wms | +------+ 1 row in set (0.01 sec)
然后我們先看從594開始恢復會是啥結果:
D:\Dev\mysql\mysql-5.7.26-winx64\data>mysqlbinlog mysql-binlog.000001 --start-position 594 --stop-position 1237 | mysql -u root -p test Enter password: ********* ERROR 1050 (42S01) at line 25: Table 't_test' already exists
報錯了,因為t_test表我們已經存在了,重復建表當然報錯了。那么恢復的開始位置我們應該跳過建表語句,可以從719開始,再來一次:
D:\Dev\mysql\mysql-5.7.26-winx64\data>mysqlbinlog mysql-binlog.000001 --start-position 719 --stop-position 1237 | mysql -u root -p test Enter password: ********* D:\Dev\mysql\mysql-5.7.26-winx64\data>
這次沒有報錯了,我們去數據庫看下數據是否恢復了:
mysql> select * from t_test; +------+ | name | +------+ | wms | | wlf | | wms | +------+ 3 rows in set (0.00 sec)
呵呵,不僅恢復了被誤刪的第一條數據,還重復插入了第二條數據。怎么解決呢?有兩個辦法:第一個是直接把t_test也drop掉,然后執行我們的一次恢復,將執行從建表到第一、第二次插入;第二個辦法是我們只恢復第一次插入,也就是只執行719到978。但如果是大量數據被我們誤刪了,那么就無法精確的知道該恢復從哪個位置開始到哪個位置結束的操作,沒關系,我們可以根據時間來恢復,把--start-position和--stop-positon改成--start-datetime和--stop-datetime。
上述mysqlbinlog命令是在binlog日志(如例子中的mysql-binlog.000001)所在目錄執行的,后面的test是我的數據庫名。最后我們再來按辦法一操作一次:
先drop表
mysql> drop table t_test; Query OK, 0 rows affected (0.05 sec)
再從頭594到1237恢復:
D:\Dev\mysql\mysql-5.7.26-winx64\data>mysqlbinlog mysql-binlog.000001 --start-position 594 --stop-position 1237 | mysql -u root -p test Enter password: ********* D:\Dev\mysql\mysql-5.7.26-winx64\data>
現在數據已經恢復正常:
mysql> select * from t_test; +------+ | name | +------+ | wlf | | wms | +------+ 2 rows in set (0.00 sec)