(一)概述
在日常MySQL數(shù)據(jù)庫運維過程中,可能會遇到用戶誤刪除數(shù)據(jù),常見的誤刪除數(shù)據(jù)操作有:
- 用戶執(zhí)行delete,因為條件不對,刪除了不應(yīng)該刪除的數(shù)據(jù)(DML操作);
- 用戶執(zhí)行update,因為條件不對,更新數(shù)據(jù)出錯(DML操作);
- 用戶誤刪除表drop table(DDL操作);
- 用戶誤清空表truncate(DDL操作);
- 用戶刪除數(shù)據(jù)庫drop database,跑路(DDL操作)
- …等
這些情況雖然不會經(jīng)常遇到,但是遇到了,我們需要有能力將其恢復(fù),下面講述如何恢復(fù)。
(二)恢復(fù)原理
如果要將數(shù)據(jù)庫恢復(fù)到故障點之前,那么需要有數(shù)據(jù)庫全備和全備之后產(chǎn)生的所有二進制日志。
全備作用 :使用全備將數(shù)據(jù)庫恢復(fù)到上一次完整備份的位置;
二進制日志作用:利用全備的備份集將數(shù)據(jù)庫恢復(fù)到上一次完整備份的位置之后,需要對上一次全備之后數(shù)據(jù)庫產(chǎn)生的所有動作進行重做,而重做的過程就是解析二進制日志文件為SQL語句,然后放到數(shù)據(jù)庫里面再次執(zhí)行。
舉個例子:小明在4月1日晚上8:00使用了mysqldump對數(shù)據(jù)庫進行了備份,在4月2日早上12:00的時候,小華不小心刪除了數(shù)據(jù)庫,那么,在執(zhí)行數(shù)據(jù)庫恢復(fù)的時候,需要使用4月1日晚上的完整備份將數(shù)據(jù)庫恢復(fù)到“4月1日晚上8:00”,那4月1日晚上8:00以后到4月2日早上12:00之前的數(shù)據(jù)如何恢復(fù)呢?就得通過解析二進制日志來對這段時間執(zhí)行過的SQL進行重做。
(三)刪庫恢復(fù)測試
(3.1)實驗?zāi)康?/p>
在本次實驗中,我直接測試刪庫,執(zhí)行drop database lijiamandb,確認是否可以恢復(fù)。
(3.2)測試過程
在測試數(shù)據(jù)庫lijiamandb中創(chuàng)建測試表test01和test02,然后執(zhí)行mysqldump對數(shù)據(jù)庫進行全備,之后執(zhí)行drop database,確認database是否可以恢復(fù)。
STEP1:創(chuàng)建測試數(shù)據(jù),為了模擬日常繁忙的生產(chǎn)環(huán)境,頻繁的操作數(shù)據(jù)庫產(chǎn)生大量二進制日志,我特地使用存儲過程和EVENT產(chǎn)生大量數(shù)據(jù)。
創(chuàng)建測試表:
use lijiamandb;create table test01
(
id1 int not null auto_increment,
name varchar(30),
primary key(id1)
);
create table test02
(
id2 int not null auto_increment,
name varchar(30),
primary key(id2)
);
創(chuàng)建存儲過程,往測試表里面插入數(shù)據(jù),每次執(zhí)行該存儲過程,往test01和test02各自插入10000條數(shù)據(jù):
CREATE DEFINER=`root`@`%` PROCEDURE `p_insert`()
BEGIN
#Routine body goes here...
DECLARE str1 varchar(30);
DECLARE str2 varchar(30);
DECLARE i int;
set i = 0;
while i 10000 do
set str1 = substring(md5(rand()),1,25);
insert into test01(name) values(str1);
set str2 = substring(md5(rand()),1,25);
insert into test02(name) values(str1);
set i = i + 1;
end while;
END
制定事件,每隔10秒鐘,執(zhí)行上面的存儲過程:
use lijiamandb;
create event if not exists e_insert
on schedule every 10 second
on completion preserve
do call p_insert();
啟動EVENT,每個10s自動向test01和test02各自插入10000條數(shù)據(jù)
mysql> show variables like '%event_scheduler%';
+----------------------------------------------------------+-------+
| Variable_name | Value |
+----------------------------------------------------------+-------+
| event_scheduler | OFF |
+----------------------------------------------------------+-------+
mysql> set global event_scheduler = on;
Query OK, 0 rows affected (0.08 sec)
--過3分鐘。。。
STEP2:第一步生成大量測試數(shù)據(jù)后,使用mysqldump對lijiamandb數(shù)據(jù)庫執(zhí)行完全備份
mysqldump -h192.168.10.11 -uroot -p123456 -P3306 --single-transaction --master-data=2 --events --routines --databases lijiamandb > /mysql/backup/lijiamandb.sql
注意:必須要添加--master-data=2,這樣才會備份集里面mysqldump備份的終點位置。
--過3分鐘。。。
STEP3:為了便于數(shù)據(jù)庫刪除前與刪除后數(shù)據(jù)一致性校驗,先停止表的數(shù)據(jù)插入,此時test01和test02都有930000行數(shù)據(jù),我們后續(xù)恢復(fù)也要保證有930000行數(shù)據(jù)。
mysql> set global event_scheduler = off;
Query OK, 0 rows affected (0.00 sec)
mysql> select count(*) from test01;
+----------+
| count(*) |
+----------+
| 930000 |
+----------+
row in set (0.14 sec)
mysql> select count(*) from test02;
+----------+
| count(*) |
+----------+
| 930000 |
+----------+
row in set (0.13 sec)
STEP4:刪除數(shù)據(jù)庫
mysql> drop database lijiamandb;
Query OK, 2 rows affected (0.07 sec)
STEP5:使用mysqldump的全備導(dǎo)入
mysql> create database lijiamandb;
Query OK, 1 row affected (0.01 sec)
mysql> exit
Bye
[root@masterdb binlog]# mysql -uroot -p123456 lijiamandb /mysql/backup/lijiamandb.sql
mysql: [Warning] Using a password on the command line interface can be insecure.
在執(zhí)行全量備份恢復(fù)之后,發(fā)現(xiàn)只有753238筆數(shù)據(jù):
[root@masterdb binlog]# mysql -uroot -p123456 lijiamandb
mysql> select count(*) from test01;
+----------+
| count(*) |
+----------+
| 753238 |
+----------+
row in set (0.12 sec)
mysql> select count(*) from test02;
+----------+
| count(*) |
+----------+
| 753238 |
+----------+
row in set (0.11 sec)
很明顯,全量導(dǎo)入之后,數(shù)據(jù)不完整,接下來使用mysqlbinlog對二進制日志執(zhí)行增量恢復(fù)。
使用mysqlbinlog進行增量日志恢復(fù)最重要的就是確定待恢復(fù)的起始位置(start-position)和終止位置(stop-position),起始位置(start-position)是我們執(zhí)行全被之后的位置,而終止位置則是故障發(fā)生之前的位置。
STEP6:確認mysqldump備份到的最終位置
[root@masterdb backup]# cat lijiamandb.sql |grep "CHANGE MASTER"
-- CHANGE MASTER TO MASTER_LOG_FILE='master-bin.000044', MASTER_LOG_POS=8526828
備份到了44號日志的8526828位置,那么恢復(fù)的起點可以設(shè)置為:44號日志的8526828。
--接下來確認要恢復(fù)的終點位置,即執(zhí)行"DROP DATABASE LIJIAMAN"之前的位置,需要到binlog里面確認。
[root@masterdb binlog]# ls
master-bin.000001 master-bin.000010 master-bin.000019 master-bin.000028 master-bin.000037 master-bin.000046 master-bin.000055
master-bin.000002 master-bin.000011 master-bin.000020 master-bin.000029 master-bin.000038 master-bin.000047 master-bin.000056
master-bin.000003 master-bin.000012 master-bin.000021 master-bin.000030 master-bin.000039 master-bin.000048 master-bin.000057
master-bin.000004 master-bin.000013 master-bin.000022 master-bin.000031 master-bin.000040 master-bin.000049 master-bin.000058
master-bin.000005 master-bin.000014 master-bin.000023 master-bin.000032 master-bin.000041 master-bin.000050 master-bin.000059
master-bin.000006 master-bin.000015 master-bin.000024 master-bin.000033 master-bin.000042 master-bin.000051 master-bin.index
master-bin.000007 master-bin.000016 master-bin.000025 master-bin.000034 master-bin.000043 master-bin.000052
master-bin.000008 master-bin.000017 master-bin.000026 master-bin.000035 master-bin.000044 master-bin.000053
master-bin.000009 master-bin.000018 master-bin.000027 master-bin.000036 master-bin.000045 master-bin.000054
# 多次查找,發(fā)現(xiàn)drop database在54號日志文件
[root@masterdb binlog]# mysqlbinlog -v master-bin.000056 | grep -i "drop database lijiamandb"
[root@masterdb binlog]# mysqlbinlog -v master-bin.000055 | grep -i "drop database lijiamandb"
[root@masterdb binlog]# mysqlbinlog -v master-bin.000055 | grep -i "drop database lijiamandb"
[root@masterdb binlog]# mysqlbinlog -v master-bin.000054 | grep -i "drop database lijiamandb"
drop database lijiamandb
# 保存到文本,便于搜索
[root@masterdb binlog]# mysqlbinlog -v master-bin.000054 > master-bin.txt
# 確認drop database之前的位置為:54號文件的9019487
# at 9019422
#200423 16:07:46 server id 11 end_log_pos 9019487 CRC32 0x86f13148 Anonymous_GTID last_committed=30266 sequence_number=30267 rbr_only=no
SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/;
# at 9019487
#200423 16:07:46 server id 11 end_log_pos 9019597 CRC32 0xbd6ea5dd Query thread_id=100 exec_time=0 error_code=0
SET TIMESTAMP=1587629266/*!*/;
SET @@session.sql_auto_is_null=0/*!*/;
/*!\C utf8 *//*!*/;
SET @@session.character_set_client=33,@@session.collation_connection=33,@@session.collation_server=33/*!*/;
drop database lijiamandb
/*!*/;
# at 9019597
#200423 16:09:25 server id 11 end_log_pos 9019662 CRC32 0x8f7b11dc Anonymous_GTID last_committed=30267 sequence_number=30268 rbr_only=no
SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/;
# at 9019662
#200423 16:09:25 server id 11 end_log_pos 9019774 CRC32 0x9b42423d Query thread_id=100 exec_time=0 error_code=0
SET TIMESTAMP=1587629365/*!*/;
create database lijiamandb
STEP7:確定了開始結(jié)束點,執(zhí)行增量恢復(fù)
開始:44號日志的8526828
結(jié)束:54號文件的9019487
這里分為3條命令執(zhí)行,起始日志文件涉及到參數(shù)start-position參數(shù),單獨執(zhí)行;中止文件涉及到stop-position參數(shù),單獨執(zhí)行;中間的日志文件不涉及到特殊參數(shù),全部一起執(zhí)行。
# 起始日志文件
# 起始日志文件
mysqlbinlog --start-position=8526828 /mysql/binlog/master-bin.000044 | mysql -uroot -p123456
# 中間日志文件
mysqlbinlog /mysql/binlog/master-bin.000045 /mysql/binlog/master-bin.000046 /mysql/binlog/master-bin.000047 /mysql/binlog/master-bin.000048 /mysql/binlog/master-bin.000049 /mysql/binlog/master-bin.000050 /mysql/binlog/master-bin.000051 /mysql/binlog/master-bin.000052 /mysql/binlog/master-bin.000053 | mysql -uroot -p123456
# 終止日志文件
mysqlbinlog --stop-position=9019487 /mysql/binlog/master-bin.000054 | mysql -uroot -p123456
STEP8:恢復(fù)結(jié)束,確認全部數(shù)據(jù)已經(jīng)還原
[root@masterdb binlog]# mysql -uroot -p123456 lijiamandb
mysql> select count(*) from test01;
+----------+
| count(*) |
+----------+
| 930000 |
+----------+
row in set (0.15 sec)
mysql> select count(*) from test02;
+----------+
| count(*) |
+----------+
| 930000 |
+----------+
row in set (0.13 sec)
(四)總結(jié)
1.對于DML操作,binlog記錄了所有的DML數(shù)據(jù)變化:
--對于insert,binlog記錄了insert的行數(shù)據(jù)
--對于update,binlog記錄了改變前的行數(shù)據(jù)和改變后的行數(shù)據(jù)
--對于delete,binlog記錄了刪除前的數(shù)據(jù)
假如用戶不小心誤執(zhí)行了DML操作,可以使用mysqlbinlog將數(shù)據(jù)庫恢復(fù)到故障點之前。
2.對于DDL操作,binlog只記錄用戶行為,而不記錄行變化,但是并不影響我們將數(shù)據(jù)庫恢復(fù)到故障點之前。
總之,使用mysqldump全備加binlog日志,可以將數(shù)據(jù)恢復(fù)到故障前的任意時刻。
到此這篇關(guān)于MySQL使用mysqldump+binlog完整恢復(fù)被刪除的數(shù)據(jù)庫的文章就介紹到這了,更多相關(guān)MySQL恢復(fù)被刪除的數(shù)據(jù)庫內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
您可能感興趣的文章:- MySQL數(shù)據(jù)庫恢復(fù)(使用mysqlbinlog命令)
- MySQL中的binlog相關(guān)命令和恢復(fù)技巧
- Mysql的Binlog數(shù)據(jù)恢復(fù):不小心刪除數(shù)據(jù)庫詳解
- mysql如何利用binlog進行數(shù)據(jù)恢復(fù)詳解
- 教你自動恢復(fù)MySQL數(shù)據(jù)庫的日志文件(binlog)
- Linux上通過binlog文件恢復(fù)mysql數(shù)據(jù)庫詳細步驟
- 解說mysql之binlog日志以及利用binlog日志恢復(fù)數(shù)據(jù)的方法
- MySQL使用binlog日志做數(shù)據(jù)恢復(fù)的實現(xiàn)
- mysql5.7使用binlog 恢復(fù)數(shù)據(jù)的方法
- 如何利用MySQL的binlog恢復(fù)誤刪數(shù)據(jù)庫詳解