盡管采取了一些管理措施來保證數據庫的安全,但是不確定的意外情況總是有可能造成數據的損失,例如意外的停電、管理員不小心的操作失誤都可能會造成數據的丟失。保證數據安全最重要的一個措施是確保對數據進行定期備份。如果數據庫中的數據丟失或者出現錯誤,可以使用備份的數據進行恢復,這樣就盡可能地降低了意外原因導致的損失。MySQL提供了多種方法對數據進行備份和恢復。
數據備份
使用MySQLdump命令備份
MySQLdump
是MySQL提供的一個非常有用的數據庫備份工具。MySQLdump
命令執行時,可以將數據庫備份成一個文本文件,該文件中實際包含了多個CREATE
和INSERT
語句,使用這些語句可以重新創建表和插入數據。
MySQLdump
備份數據庫語句的基本語法格式如下:
mysqldump -u user -h host -ppassword dbname [tbname, [tbname...]] > filename.sql
user
表示用戶名稱;host
表示登錄用戶的主機名稱;password
為登錄密碼;dbname
為需要備份的數據庫名稱;tbname
為dbname
數據庫中需要備份的數據表,可以指定多個需要備份的表;右箭頭符號>
告訴MySQLdump
將備份數據表的定義和數據寫入備份文件;filename.sql
為備份文件的名稱。
- 使用MySQLdump備份單個數據庫中的所有表
為了更好地理解MySQLdump工具是如何工作的,這里給出一個完整的數據庫例子。首先登錄MySQL,按下面數據庫結構創建booksDB數據庫和各個表,並插入數據記錄。數據庫和表定義如下:
create database booksDB;
use booksDB;
create table books
(
books int not null primary key,
bk_title varchar(50) not null,
copyright year not null
);
insert into books value (11078, 'Learning Mysql', 2010),
(11079, 'Study html', 2011),
(11080, 'How to use php', 2012),
(11081, 'Teach yourself javascript', 2013),
(11082, 'Guide to Mysql8.0', 2014);
create table authors
(
auth_id int not null primary key,
auth_name varchar(20),
auth_gender char(1)
);
insert into authors values (1001, 'WriteA', 'f'),
(1002, 'WriteB', 'm'),
(1003, 'WriteC', 'n'),
(1004, 'WriteD', 'l'),
(1005, 'WriteE', 'b');
create table authorbook
(
auth_id int not null,
bk_id int not null,
primary key(auth_id, bk_id),
foreign key(auth_id) references authors(auth_id),
foreign key(bk_id) references books(books)
);
insert into authorbook values (1001, 11078),
(1002, 11079),
(1003, 11080),
(1004, 11081),
(1005, 11082);
完成數據插入后打開操作系統命令行輸入窗口,輸入備份命令如下:
C:\>mysqldump -u root -p booksdb > D:/booksdb_20220205.sql
Enter password: ****
輸入的路徑必須存在,路徑下文件夾也存在。
輸入密碼之后,MySQL便對數據庫進行了備份,在D:\
文件夾下面查看剛才備份過的文件,使用文本查看器打開文件可以看到其部分文件內容大致如下:
-- MySQL dump 10.13 Distrib 8.0.28, for Win64 (x86_64)
--
-- Host: localhost Database: booksdb
-- ------------------------------------------------------
-- Server version 8.0.28
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!50503 SET NAMES utf8mb4 */;
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SET TIME_ZONE='+00:00' */;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
--
-- Table structure for table `authorbook`
--
DROP TABLE IF EXISTS `authorbook`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `authorbook` (
`auth_id` int NOT NULL,
`bk_id` int NOT NULL,
PRIMARY KEY (`auth_id`,`bk_id`),
KEY `bk_id` (`bk_id`),
CONSTRAINT `authorbook_ibfk_1` FOREIGN KEY (`auth_id`) REFERENCES `authors` (`auth_id`),
CONSTRAINT `authorbook_ibfk_2` FOREIGN KEY (`bk_id`) REFERENCES `books` (`books`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `authorbook`
--
LOCK TABLES `authorbook` WRITE;
/*!40000 ALTER TABLE `authorbook` DISABLE KEYS */;
INSERT INTO `authorbook` VALUES (1001,11078),(1002,11079),(1003,11080),(1004,11081),(1005,11082);
/*!40000 ALTER TABLE `authorbook` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `authors`
--
DROP TABLE IF EXISTS `authors`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `authors` (
`auth_id` int NOT NULL,
`auth_name` varchar(20) DEFAULT NULL,
`auth_gender` char(1) DEFAULT NULL,
PRIMARY KEY (`auth_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `authors`
--
LOCK TABLES `authors` WRITE;
/*!40000 ALTER TABLE `authors` DISABLE KEYS */;
INSERT INTO `authors` VALUES (1001,'WriteA','f'),(1002,'WriteB','m'),(1003,'WriteC','n'),(1004,'WriteD','l'),(1005,'WriteE','b');
/*!40000 ALTER TABLE `authors` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `books`
--
DROP TABLE IF EXISTS `books`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `books` (
`books` int NOT NULL,
`bk_title` varchar(50) NOT NULL,
`copyright` year NOT NULL,
PRIMARY KEY (`books`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `books`
--
LOCK TABLES `books` WRITE;
/*!40000 ALTER TABLE `books` DISABLE KEYS */;
INSERT INTO `books` VALUES (11078,'Learning Mysql',2010),(11079,'Study html',2011),(11080,'How to use php',2012),(11081,'Teach yourself javascript',2013),(11082,'Guide to Mysql8.0',2014);
/*!40000 ALTER TABLE `books` ENABLE KEYS */;
UNLOCK TABLES;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
-- Dump completed on 2022-02-05 22:23:35
可以看到,備份文件包含了一些信息,文件開頭首先表明了備份文件使用的MySQLdump工具的版本號;然后是備份賬戶的名稱和主機信息,以及備份的數據庫的名稱,最后是MySQL服務器的版本號,在這里為8.0.28。
備份文件接下來的部分是一些SET語句,這些語句將一些系統變量值賦給用戶定義變量,以確保被恢復的數據庫的系統變量和原來備份時的變量相同。
備份文件中以“--”字符開頭的行為注釋語句;以“/!”開頭、“/”結尾的語句為可執行的MySQL注釋,這些語句可以被MySQL執行,但在其他數據庫管理系統中將被作為注釋忽略,以提高數據庫的可移植性。
- 使用
MySQLdump
備份數據庫中的某個表
MySQLdump
還可以備份數據中的某個表,其語法格式為:
mysqldump -u user -h host -p dbname [tbname, [tbname...]] > filename.sql
tbname
表示數據庫中的表名,多個表名之間用空格隔開。
備份表和備份數據庫中所有表的語句中不同的地方在於,要在數據庫名稱dbname
之后指定需要備份的表名稱。
C:\>mysqldump -u root -p booksdb books > D:/booksdb_20220206.sql
Enter password: ****
該語句創建名稱為booksdb_20220206.sql的備份文件,文件中包含了前面介紹的SET語句等內容,不同的是,該文件只包含books
表的CREATE
和INSERT
語句。
- 使用
MySQLdump
備份多個數據庫
如果要使用MySQLdump
備份多個數據庫,就需要使用--databases
參數。備份多個數據庫的語句格式如下:
mysqldump -u user -h host -p --databases [dbname, [dbname...] > filename.sql
使用--databases
參數之后,必須指定至少一個數據庫的名稱,多個數據庫名稱之間用空格隔開。
比如:
C:\>mysqldump -u root -p --databases booksdb test_db> D:/booksdb_20220207.sql
另外,使用--all-databases參數可以備份系統中所有的數據庫,語句如下:
mysqldump -u user -h host -p --all-databases > filename.sql
使用參數--all-databases
時,不需要指定數據庫名稱。
使用MySQLdump
備份服務器中的所有數據庫,輸入語句如下:
mysqldump -u root -p --all-databases > D:/alldbinMySQL.sql
該語句創建名稱為alldbinMySQL.sql
的備份文件,文件中包含了對系統中所有數據庫的備份信息。
如果在服務器上進行備份,並且表均為MyISAM表,就應該考慮使用MySQLhotcopy,因為可以更快地進行備份和恢復。
直接復制整個數據庫目錄
因為MySQL表保存為文件方式,所以可以直接復制MySQL數據庫的存儲目錄及文件進行備份。MySQL的數據庫目錄位置不一定相同,在Windows平台下,MySQL 8.0存放數據庫的目錄通常默認為“C:\Documents and Settings\All Users\ApplicationData\MySQL\MySQL Server 8.0\data”
或者其他用戶自定義目錄;在Linux平台下,數據庫目錄位置通常為/var/lib/MySQL/
,不同Linux版本下目錄會有所不同。
這是一種簡單、快速、有效的備份方式。要想保持備份的一致性,備份前需要對相關表執行LOCK TABLES
操作,然后對表執行FLUSH TABLES
。這樣當復制數據庫目錄中的文件時,允許其他客戶繼續查詢表。需要FLUSH TABLES
語句來確保開始備份前將所有激活的索引頁寫入硬盤。當然,也可以停止MySQL服務再進行備份操作。
這種方法雖然簡單,但並不是最好的方法。因為這種方法對InnoDB
存儲引擎的表不適用。使用這種方法備份的數據最好恢復到相同版本的服務器中,不同的版本可能不兼容。
在MySQL版本號中,第一個數字表示主版本號,主版本號相同的MySQL數據庫文件格式相同
使用MySQLhotcopy工具快速備份
MySQLhotcopy
是一個Perl腳本,最初由Tim Bunce編寫並提供。它使用LOCK TABLES、FLUSH TABLES
和cp
或scp
來快速備份數據庫。它是備份數據庫或單個表最快的途徑,但它只能運行在數據庫目錄所在的機器上,並且只能備份MyISAM
類型的表。MySQLhotcopy
在UNIX
系統中運行。
數據恢復
管理人員操作的失誤、計算機故障以及其他意外情況,都會導致數據的丟失和破壞。當數據丟失或意外破壞時,可以通過恢復已經備份的數據盡量減少數據丟失和破壞造成的損失。
使用MySQL命令恢復
備份的sql文件中包含CREATE、INSERT語句(有時也會有DROP語句)。MySQL命令可以直接執行文件中的這些語句。其語法如下:
mysql -u user -p [dbname] < filename.sql
user
是執行backup.sql
中語句的用戶名;-p
表示輸入用戶密碼;dbname
是數據庫名。如果filename.sql
文件為MySQLdump
工具創建的包含創建數據庫語句的文件,執行的時候不需要指定數據庫名。
將之前得備份導入數據庫:
C:\>mysql -u root -p booksdb < D:/booksdb_20220206.sql
Enter password: ****
這里得數據庫必須存在否者會報錯
直接復制到數據庫目錄
如果數據庫通過復制數據庫文件備份,可以直接復制備份的文件到MySQL數據目錄下實現恢復。通過這種方式恢復時,保存備份數據的數據庫和待恢復的數據庫服務器的主版本號必須相同。而且這種方式只對MyISAM引擎的表有效,對於InnoDB引擎的表不可用。
對於InnoDB引擎得表,需要把一個表的文件夾+ibdata1(innodb才需要拷貝這個)拷貝進去,刪掉ib_logfile1和ib_logfile0兩個文件,重新運行mysql。
ibdata1文件一定要賦予執行權限。
執行恢復以前關閉MySQL服務,將備份的文件或目錄覆蓋MySQL的data目錄,啟動MySQL服務。對於Linux/UNIX操作系統來說,復制完文件需要將文件的用戶和組更改為MySQL運行的用戶和組,通常用戶是MySQL,組也是MySQL。
數據庫遷移
數據庫遷移就是把數據從一個系統移動到另一個系統上。數據遷移有以下原因:
- 需要安裝新的數據庫服務器。
- MySQL版本更新。
- 數據庫管理系統的變更(如從Microsoft SQL Server遷移到MySQL)。
相同版本的MySQL數據庫之間的遷移
相同版本的MySQL數據庫之間的遷移就是在主版本號相同的MySQL數據庫之間進行數據庫移動。遷移過程其實就是在源數據庫備份和目標數據庫恢復過程的組合。
在講解數據庫備份和恢復時,已經知道最簡單的方式是通過復制數據庫文件目錄,但是此種方法只適用於MyISAM
引擎的表。而對於InnoDB表,不能用直接復制文件的方式備份數據庫,因此最常用和最安全的方式是使用MySQLdump
命令導出數據,然后在目標數據庫服務器使用MySQL命令導入。
比如,將www.abc.com
主機上的MySQL數據庫全部遷移到www.bcd.com
主機上。在www.abc.com
主機上執行的命令如下:
mysqldump -h www.bac.com -uroot -ppassword dbname | mysql -h www.bcd.com -uroot -ppassword
MySQLdump
導入的數據直接通過管道符“|”
傳給MySQL命令導入到主機www.bcd.com
數據庫中,dbname
為需要遷移的數據庫名稱,如果要遷移全部的數據庫,可使用參數--all-databases
。
不同版本得MySQL數據庫之間得遷移
因為數據庫升級等原因,需要將較舊版本MySQL數據庫中的數據遷移到較新版本的數據庫中。MySQL服務器升級時,需要先停止服務,然后卸載舊版本,並安裝新版的MySQL,這種更新方法很簡單,如果想保留舊版本中的用戶訪問控制信息,就需要備份MySQL中的MySQL數據庫,在新版本MySQL安裝完成之后,重新讀入MySQL備份文件中的信息。
舊版本與新版本的MySQL可能使用不同的默認字符集,例如MySQL8.0版本之前,默認字符集為latin1
,而MySQL 8.0版本默認字符集為utf8mb4
。數據庫中有中文數據的,遷移過程中需要對默認字符集進行修改,不然可能無法正常顯示結果。
新版本會對舊版本有一定兼容性。從舊版本的MySQL向新版本的MySQL遷移時,對於MyISAM引擎的表,可以直接復制數據庫文件,也可以使用MySQLhotcopy工具、MySQLdump工具。對於InnoDB引擎的表,一般只能使用MySQLdump
將數據導出。然后使用MySQL命令導入到目標服務器上。從新版本向舊版本MySQL遷移數據時要特別小心,最好使用MySQLdump
命令導出,然后導入目標數據庫中。
不同數據庫之間的遷移
不同類型的數據庫之間的遷移,是指把MySQL的數據庫轉移到其他類型的數據庫,例如從MySQL遷移到Oracle,從Oracle遷移到MySQL,從MySQL遷移到SQL Server等。
遷移之前,需要了解不同數據庫的架構,比較它們之間的差異。不同數據庫中定義相同類型的數據的關鍵字可能會不同。例如,MySQL中日期字段分為DATE和TIME兩種,而Oracle日期字段只有DATE。另外,數據庫廠商並沒有完全按照SQL標准來設計數據庫系統,導致不同的數據庫系統的SQL語句有差別。例如,MySQL幾乎完全支持標准SQL語言,而Microsoft SQL Server使用的是T-SQL語言,T-SQL中有一些非標准的SQL語句,因此在遷移時必須對這些語句進行語句映射處理。
數據庫遷移可以使用一些工具,例如在Windows系統下,可以使用MyODBC實現MySQL和SQL Server之間的遷移。MySQL官方提供的工具MySQL Migration Toolkit
也可以在不同數據庫間進行數據遷移。