Fork me on GitHub

MySQL数据备份及恢复

一、数据备份

(一)mysqldump

1、命令格式

MySQL自带了一个很好使用的数据库备份命令,就是mysqldump,语法如下:

mysqldump -u 用户名 -p 数据库名 > 备份文件名

 2、实例说明

-- 查看备份前数据
[root@hadoop-slave1 temp]# mysql -uroot -p123456 -e "use crm_db;show tables;select *from userinfo;"
+------------------+
| Tables_in_crm_db |
+------------------+
| userinfo         |
+------------------+
+----+----------+-----+
| id | username | age |
+----+----------+-----+
|  1 | zhangsan |  24 |
+----+----------+-----+

-- 执行备份命令
[root@hadoop-slave1 temp]# mysqldump -uroot -p123456 crm_db > /temp/crm_db_bak.sql

-- 查看备份结果
[root@hadoop-slave1 temp]# egrep -v "#|\*|--|^$" /temp/crm_db_bak.sql 
DROP TABLE IF EXISTS `userinfo`;
CREATE TABLE `userinfo` (
  `id` int(4) NOT NULL AUTO_INCREMENT,
  `username` varchar(32) DEFAULT NULL,
  `age` tinyint(2) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`),
  UNIQUE KEY `index_uni_username` (`username`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
LOCK TABLES `userinfo` WRITE;
INSERT INTO `userinfo` VALUES (1,'zhangsan',24);
UNLOCK TABLES;

(二)参数说明

上面使用mysqldump简单的方式进行备份,当然mysqldump还有很多参数。

1、--default-character-set

该参数指定了备份的字符集,可解决备份乱码的问题。

[root@hadoop-slave1 temp]# mysqldump -uroot -p123456 --default-character-set=utf8 crm_db > /temp/crm_db_bak.sql

2、-A

-A参数的作用是备份所有的库,例如:

-- 备份命令
[root@hadoop-slave1 /]# mysqldump -uroot -p123456 -A --events  > /temp/all.sql

3、-B

-B参数的作用是在备份中:

  • 增加了创建数据库
  • 连接数据库(use database)
-- 进行备份
[root@hadoop-slave1 temp]# mysqldump -uroot -p123456 -B crm_db > /temp/crm_db_bak.sql


-- 查看内容
CREATE DATABASE /*!32312 IF NOT EXISTS*/ `crm_db` 
USE `crm_db`;

DROP TABLE IF EXISTS `userinfo`;
CREATE TABLE `userinfo` (
  `id` int(4) NOT NULL AUTO_INCREMENT,
  `username` varchar(32) DEFAULT NULL,
  `age` tinyint(2) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`),
  UNIQUE KEY `index_uni_username` (`username`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

LOCK TABLES `userinfo` WRITE;
INSERT INTO `userinfo` VALUES (1,'zhangsan',24);
UNLOCK TABLES;

可以看到这与之前的不同在于多了以下两条语句:

CREATE DATABASE /*!32312 IF NOT EXISTS*/ `crm_db`  -- 创建数据库
USE `crm_db`; -- 连接数据库

4、--compact

该参数可以优化备份文件大小,减少输出注释。该参数适合测试时使用。

-- 备份命令
[root@hadoop-slave1 temp]# mysqldump -uroot -p123456 --compact crm_db > /temp/crm_db_compat_bak_.sql

-- 备份文件的完整内容
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `userinfo` (
  `id` int(4) NOT NULL AUTO_INCREMENT,
  `username` varchar(32) DEFAULT NULL,
  `age` tinyint(2) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`),
  UNIQUE KEY `index_uni_username` (`username`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
INSERT INTO `userinfo` VALUES (1,'zhangsan',24);

5、gzip

gzip可以对MySQL备份文件的内容进行压缩,压缩效率提升3倍左右。

-- 命令
[root@hadoop-slave1 temp]# mysqldump -uroot -p123456 -B crm_db|gzip > /temp/crm_db_bak_gzip.sql.gz

可以查看普通备份和压缩后的文件大小比较:

[root@hadoop-slave1 temp]# ll /temp/
total 8
-rw-r--r--. 1 root root  804 Aug 29 16:58 crm_db_bak_gzip.sql.gz
-rw-r--r--. 1 root root 2141 Aug 29 16:58 crm_db_bak.sql

6、-F

-F参数用于刷新 binlog参数,在/etc/my.cnf配置文件中如果启用了log-bin就会在安装的数据目录中生成binlog日志信息。

在没有进行备份时,和binlog相关的文件有:

[root@hadoop-slave1 data]# ll
...
-rw-rw----. 1 mysql mysql      107 Aug 29 22:50 mysql-bin.000001
-rw-rw----. 1 mysql mysql       19 Aug 29 22:50 mysql-bin.index
...

使用-F参数进行备份:

-- 进行备份
[root@hadoop-slave1 data]# mysqldump -uroot -p123456 -A -B -F --events  > /temp/all.sql

-- 查看binlog相关文件
[root@hadoop-slave1 data]# ll
...
-rw-rw----. 1 mysql mysql      150 Aug 29 23:14 mysql-bin.000001
-rw-rw----. 1 mysql mysql      150 Aug 29 23:14 mysql-bin.000002
-rw-rw----. 1 mysql mysql      150 Aug 29 23:14 mysql-bin.000003
-rw-rw----. 1 mysql mysql      107 Aug 29 23:14 mysql-bin.000004
-rw-rw----. 1 mysql mysql       76 Aug 29 23:14 mysql-bin.index
...

  binlog文件被刷新了,也就意味着如果进行数据恢复,只需要从mysql-bin.000004之后进行增量恢复,这个文件之前的已经进行了全量备份了(在all.sql文件中)。这个参数主要就是切割binlog日志,记录备份的位置。防止恢复数据进行全量恢复而出错。

7、--master-data

这个参数也是记录binlog的位置,找到恢复的点,例如:

-- --master-data使用
[root@hadoop-slave1 data]# mysqldump -uroot -p123456 --compact --master-data -B crm_db  > /temp/crm_db.sql

-- 备份的文件内容
CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000004', MASTER_LOG_POS=107;

CREATE DATABASE /*!32312 IF NOT EXISTS*/ `crm_db` /*!40100 DEFAULT CHARACTER SET utf8 */;

USE `crm_db`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `userinfo` (
  `id` int(4) NOT NULL AUTO_INCREMENT,
  `username` varchar(32) DEFAULT NULL,
  `age` tinyint(2) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`),
  UNIQUE KEY `index_uni_username` (`username`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
INSERT INTO `userinfo` VALUES (1,'zhangsan',24);

可以看到备份的文件内容中,多了一行:

CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000004', MASTER_LOG_POS=107;

这是记录了binlog日志的信息,也就是说在这个位置之前的已经全部备份了,只需要通过binlog恢复这个点之后的内容即可。

对于查看mysql-bin.000004文件的内容,通过mysqlbinlog命令:

root@hadoop-slave1 data]# mysqlbinlog mysql-bin.000004

(三)备份库、表练习

1、多库备份

假设现在数据库中有多个库,上述使用的一直是一个库crm_db为例:现在新建一个库crm_db_1,然后同时进行备份。

-- 显示库
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| crm_db             |
| crm_db_1           |
| mysql              |
| performance_schema |
+--------------------+
5 rows in set (0.00 sec)

-- 同时备份crm_db、crm_db_1库
[root@hadoop-slave1 temp]# mysqldump -uroot -p123456 -B crm_db crm_db_1|gzip > /temp/crm_db_all_bak.sql.gz

上面的-B参数在生产环境常用,并且有以下的功能:

  • 后面可以接多个库进行备份
  • 备份文件中会增加创建数据库的信息(create database dbname...)
  • 备份文件中会增加连接数据库的信息(use dbname)

2、分库备份

  上面是对多个库进行备份,并且备份到了一个备份文件中了,那么如何将每一个库都备份一个自己独有的备份文件呢?分库备份就是一个备份语句备份一个库,如果有多个库就执行多条相同的备份单个库的备份语句。注意的是每一个库的备份文件名可以用其库名代替,后面.sql即可。

...
mysqldump -uroot -p123456 -B crm_db|gzip > /temp/crm_db_bak_gzip.sql.gz mysqldump -uroot -p123456 -B crm_db_1|gzip > /temp/crm_db_1_bak_gzip.sql.gz
...

上面就是一条一条的写,但假如有1000个库怎么办,下面有两种方式可以进行分库备份:

  • 法一
-- 备份命令
[root@hadoop-slave1 temp]# mysql -uroot -p123456 -e "show databases;"|grep -Evi "database|infor|perfor"|sed -r  \
's#^([a-z].*$)#mysqldump -uroot -p123456 --events -B \1|gzip>/temp/\1.sql.gz#g'|bash -- 备份结果 [root@hadoop-slave1 temp]# ll /temp/ total 152 -rw-r--r--. 1 root root 530 Aug 29 19:18 crm_db_1.sql.gz -rw-r--r--. 1 root root 820 Aug 29 19:18 crm_db.sql.gz -rw-r--r--. 1 root root 144380 Aug 29 19:18 mysql.sql.gz
  • 法二

首先创建一个脚本gen_sql.sh:

for dbname in `mysql -uroot -p123456 -e "show databases;"|grep -Evi "database|infor|perfor"`
do
  mysqldump -uroot -p123456 --events -B $dbname|gzip>/temp/${dbname}_bak.sql.gz
done

然后执行:

[root@hadoop-slave1 scripts]# sh gen_sql.sh 

这样与第一种方式产生的结果一样。

分库的意义就是,如果某一个库出现问题时只需要备份这一个库就可以了,而将所有的库备份在一个备份文件中,这样恢复起来比较麻烦。

3、单表备份

语法:

mysqldump -uroot 用户名 -p 数据库名 表名 > 备份文件名

例如:

[root@hadoop-slave1 /]# mysqldump -uroot -p123456 crm_db userinfo > /temp/t1.sql

注意:不要加-B参数,因为库名后面就是表名。

4、多表备份

语法:

mysqldump -uroot 用户名 -p 数据库名 表名1 表名2 > 备份文件名

例如:

-- 备份命令
[root@hadoop-slave1 /]# mysqldump -uroot -p123456 crm_db userinfo > /temp/t1.sql

-- 备份内容
DROP TABLE IF EXISTS `userinfo`;
CREATE TABLE `userinfo` (
  `id` int(4) NOT NULL AUTO_INCREMENT,
  `username` varchar(32) DEFAULT NULL,
  `age` tinyint(2) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`),
  UNIQUE KEY `index_uni_username` (`username`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
LOCK TABLES `userinfo` WRITE;
INSERT INTO `userinfo` VALUES (1,'zhangsan',24);
UNLOCK TABLES;

  如果库名后紧跟多个表的时候会将多个表写入同一个备份文件,这样的话如果向恢复某一个表时很难将备份文件拆开,那么这也就意味着我们需要像分库一样进行分表备份。那么又该如何进行分表备份呢?其实只需要每条语句备份一个表即可:

...
mysqldump -uroot -p123456 crm_db userinfo > /temp/t1.sql
mysqldump -uroot -p123456 crm_db product> /temp/t2.sql
...

  当然,你可以像分库备份一样写一个脚本文件来进行备份。

5、备份数据库表结构

 有时候我们只需要备份数据表结构而不需要数据,这是需要使用到-d参数。

-- 备份表结构
[root@hadoop-slave1 /]# mysqldump -uroot -p123456 -B -d crm_db > /temp/crm_db__bak.sql

-- 查看备份
[root@hadoop-slave1 /]# egrep -v "#|\*|--|^$" /temp/crm_db__bak.sql 
USE `crm_db`;
DROP TABLE IF EXISTS `userinfo`;
CREATE TABLE `userinfo` (
  `id` int(4) NOT NULL AUTO_INCREMENT,
  `username` varchar(32) DEFAULT NULL,
  `age` tinyint(2) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`),
  UNIQUE KEY `index_uni_username` (`username`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

6、备份数据表数据

上面是只备份数据表结构,那么如果只想备份数据表的数据,就使用-t参数:

-- 备份命令
[root@hadoop-slave1 /]# mysqldump -uroot -p123456 -t crm_db > /temp/crm_db_bak.sql

-- 备份内容
LOCK TABLES `userinfo` WRITE;INSERT INTO `userinfo` VALUES (1,'zhangsan',24);
UNLOCK TABLES;

(四)mysqldump关键参数总结

-- 参数查看通过
[root@hadoop-slave1 data]# mysqldump --help

-- 以下关键参数说明
1-A备份所有的库
2-B指定多个库,增加建库和use语句
3--compact 去掉注释,适合调试,不用于生产
4-F刷新binlog日志
5--master-data 增加binlog日志文件名和对应的位置点
6-d只备份表结构
7、t 只备份表数据
8--single-transaction 适合innodb事务数据库备份,保证数据在备份时的一致性,
设定本次会话的隔离级别为REPEATABLE READ,确保本次会话dump是,不会看到其它会话已经提交的数据
9-l,--local-table Locak all tables for read 10-x,--local-all-tables Local all tables across all databases -- 推荐使用的innodb备份命令 mysqldump -uroot -p123456 -A -B -F --master-data=2 --events --single-transaction|gzip>/temp/all.sql.gz -- myisam备份命令 mysqldump -uroot -p123456 -A -B -F --master-data=2 -x --events |gzip>/temp/all.sql.gz

二、数据恢复

(一)source命令恢复

先进行备份,然后通过source命令恢复:

-- 备份
[root@hadoop-slave1 /]# mysqldump -uroot -p123456 -B crm_db > /temp/crm_db_bak.sql
-- 查看备份结果
[root@hadoop-slave1 /]# ll /temp/*
-rw-r--r--. 1 root root 2145 Aug 30 07:40 /temp/crm_db_bak.sql

-- 删除已经备份的库
[root@hadoop-slave1 /]# mysql -uroot -p123456 -e 'drop database crm_db;show databases;' 
+--------------------+
| Database           |
+--------------------+
| information_schema |
| crm_db_1           |
| mysql              |
| performance_schema |
+--------------------+

-- 恢复备份,需要进入MySQL命令行中
[root@hadoop-slave1 /]# mysql -uroot -p123456 -e 'source /temp/crm_db_bak.sql'

(二)mysql命令恢复(标准)

1、备份时带-B参数

-B参数在备份时有连接数据库和创建数据库的作用,所以如果在备份时指定了该参数,那么在恢复时就无需指定具体的恢复的数据库:

-- 恢复备份
[root@hadoop-slave1 /]# mysql -uroot -p123456 < /temp/crm_db_bak.sql 

-- 查看结果
[root@hadoop-slave1 /]# mysql -uroot -p123456 -e "show databases;"
+--------------------+
| Database           |
+--------------------+
| information_schema |
| crm_db             |
| crm_db_1           |
| mysql              |
| performance_schema |
+--------------------+

2、备份时未带-B参数

这也就意味着在恢复数据库数据时必须指定恢复到那个数据库,并且这个数据库已经是存在的。

-- 恢复crm_db1中的数据,crm_db1已经存在
[root@hadoop-slave1 /]# mysql -uroot -p123456 crm_db1 < /temp/crm_db1_bak.sql 

(三)分库、分表备份数据恢复

对于分库、分表的数据,通过脚本读取指定的库、表,使用mysql命令恢复。

-- 生成crm_db、crm_db1的备份文件
[root@hadoop-slave1 /]# mysql -uroot -p123456 -e "show databases;"|grep -Evi "database|infor|perfor|mysql"|sed -r  \
> 's#^([a-z].*$)#mysqldump -uroot -p123456 --events -B \1|gzip>/temp/\1.sql.gz#g'|bash

-- 查看备份文件
[root@hadoop-slave1 /]# ls /temp/
crm_db_1.sql.gz  crm_db.sql.gz

-- 进入到备份文件所在的目录,然后对其解压
[root@hadoop-slave1 temp]# ls
crm_db_1.sql.gz  crm_db.sql.gz
[root@hadoop-slave1 temp]# gzip -d *
[root@hadoop-slave1 temp]# ls
crm_db_1.sql  crm_db.sql

-- 通过脚本进行恢复,可先删除原先的库
[root@hadoop-slave1 temp]# for dbname in `ls *.sql|sed 's#.sql##g'`;do mysql -uroot -p123456 <${dbname}.sql;done

-- 查看所有的库
[root@hadoop-slave1 temp]# mysql -uroot -p123456 -e 'show databases;'
+--------------------+
| Database           |
+--------------------+
| information_schema |
| crm_db             |
| crm_db_1           |
| mysql              |
| performance_schema |
+--------------------+

(四)binlog日志恢复

MySQL的binlog日志用于记录MySQL中的增、删、该操作,当你没有备份时就只能依靠它来进行数据的恢复了。

1、恢复的种类

  • 全库
root@hadoop-slave1 data]# mysqlbinlog mysql-bin.000002 > all.sql
  • 分库

比如从binlog日志中抽离出crm_db的sql操作信息:

root@hadoop-slave1 data]# mysqlbinlog -d crm_db mysql-bin.000002 > crm_db.sql

2、增量恢复的方式

  • 基于位置点的增量恢复
 mysqlbinlog  mysql-bin.000002 --start-position=107 --stop-position=208 -r db.sql

 注意:结尾的日志比较特殊,不会被包含,即输出208以前的日志。

 如果开始位置到结束,则无需制定--stop-position参数:

 mysqlbinlog  mysql-bin.000002 --start-position=107 -r db.sql

如果没有指定--start-position参数,则是开始到指定的结束位置:

 mysqlbinlog  mysql-bin.000002 --stop-position=208 -r db.sql
  • 基于时间的增量恢复
 mysqlbinlog  mysql-bin.000002 --start-datetime='2020-8-30 11:10:20' \
--stop-datetime='2020-8-30 14:30:20' -r db.sql

(五)数据备份、恢复实战

现在假如有这样的场景,数据库crm_db中的数据在某个时间点操作失误,想恢复数据。

1、查看crm_db数据库相关信息

[root@hadoop-slave1 /]# mysql -uroot -p123456 -e 'use crm_db;show tables;select * from userinfo;' 
+------------------+
| Tables_in_crm_db |
+------------------+
| userinfo         |
+------------------+
+----+----------+-----+
| id | username | age |
+----+----------+-----+
|  1 | zhangsan |  24 |
|  2 | lisi     |  32 |
|  3 | wangwu   |  45 |
+----+----------+-----+

2、对crm_db进行备份

[root@hadoop-slave1 /]# mysqldump -uroot -p123456 -B crm_db > /temp/crm_db.sql 
[root@hadoop-slave1 /]# ll /temp/
total 4
-rw-r--r--. 1 root root 2175 Aug 30 09:46 crm_db.sql

3、异常产生

在这一步由于更改数据导致数据异常:

mysql> update userinfo set username='zhaoliu';
Query OK, 3 rows affected (0.00 sec)
Rows matched: 3  Changed: 3  Warnings: 0

mysql> select * from userinfo;
+----+----------+-----+
| id | username | age |
+----+----------+-----+
|  1 | zhaoliu  |  24 |
|  2 | zhaoliu  |  32 |
|  3 | zhaoliu  |  45 |
+----+----------+-----+
3 rows in set (0.00 sec)

由于update使用不当,导致错误产生,此时需要进行恢复,但是在恢复的过程中仍旧会有新的数据不断插入,所以需要将binlog日志先进行分割。

4、binlog日志分割

在数据库不停止服务时,进行日志分割:

-- 分割前文件
[root@hadoop-slave1 /]# ll /application/mysql-5.5.32/data/mysql-bin*
-rw-rw----. 1 mysql mysql 626 Aug 30 09:57 /application/mysql-5.5.32/data/mysql-bin.000001
-rw-rw----. 1 mysql mysql  19 Aug 30 09:51 /application/mysql-5.5.32/data/mysql-bin.index

--分割
[root@hadoop-slave1 /]# mysqladmin -uroot -p123456 flush-log

-- 分割后文件
[root@hadoop-slave1 /]# ll /application/mysql-5.5.32/data/mysql-bin*
-rw-rw----. 1 mysql mysql 669 Aug 30 10:05 /application/mysql-5.5.32/data/mysql-bin.000001
-rw-rw----. 1 mysql mysql 107 Aug 30 10:05 /application/mysql-5.5.32/data/mysql-bin.000002
-rw-rw----. 1 mysql mysql  38 Aug 30 10:05 /application/mysql-5.5.32/data/mysql-bin.index

分割后多了一个mysql-bin.000002文件,也就是说后面写的内容都会写在这个文件中,现在需要处理的就是mysql-bin.000001文件。

5、备份恢复

首先,我们将还未出错前的数据通过备份文件crm_db.sql进行恢复:

-- 通过备份恢复
[root@hadoop-slave1 temp]# mysql -uroot -p123456 < /temp/crm_db.sql 

-- 查看数据
[root@hadoop-slave1 temp]# mysql -uroot -p123456 -e 'use crm_db;select * from userinfo;' 
+----+----------+-----+
| id | username | age |
+----+----------+-----+
|  1 | zhangsan |  24 |
|  2 | lisi     |  32 |
|  3 | wangwu   |  45 |
+----+----------+-----+

现在恢复的是备份前的数据,缺少的是备份的时间点到出错这段时间的数据,那么这段时间只能通过binlog日志来获取了。

6、binlog恢复数据

-- binlog日志生成sql
[root@hadoop-slave1 data]# mysqlbinlog -d crm_db mysql-bin.000001 > bin.sql

-- 删除bin.sql中update更新的语句,然后恢复
[root@hadoop-slave1 data]# mysql -uroot -p123456 crm_db < bin.sql 

-- 查看数据
[root@hadoop-slave1 data]# mysql -uroot -p123456 -e 'use crm_db;select * from userinfo;' 
+----+----------+-----+
| id | username | age |
+----+----------+-----+
|  1 | zhangsan |  24 |
|  2 | lisi     |  32 |
|  3 | wangwu   |  45 |
+----+----------+-----+

上面恢复的数据时备份时间点到出错这段时间的数据,那么出错之后的数据因为进行了日志分割,所以它在第二个binlog日志文件中,只需要再将其恢复即可:

-- 恢复mysql-bin.000002中的数据
[root@hadoop-slave1 data]# mysqlbinlog -d crm_db mysql-bin.000002 > bin2.sql
[root@hadoop-slave1 data]# mysql -uroot -p123456 crm_db < bin2.sql 

 

posted @ 2020-08-30 13:14  iveBoy  阅读(445)  评论(0编辑  收藏  举报
TOP