mysql数据备份与恢复
1. 完全备份
-
完全备份是对整个数据库的备份、数据库结构和文件结构的备份
-
完全备份保存的是备份完成时刻的数据库
-
完全备份是增量备份的基础
1.1 物理冷备份与恢复
1.1.1 关闭数据库,打包备份
systemctl stop mysqld mkdir /backup tar zcvf /backup/mysql_all-$(date +%F).tar.gz /usr/local/mysql/data/
1.1.2 恢复数据库
将备份数据mv成线上库文件夹
mkdir /bak mv /usr/local/mysql/data/ /bak/ mkdir restore tar zxvf /backup/mysql_all-2020-12-24.tar.gz -C restore/ mv restore/usr/local/mysql/data/ /usr/local/mysql/ systemctl start mysqld
1.2 mysqldump逻辑备份
1.2.1 备份数据库
#备份所有库
mysqldump -u 用户名 -p [密码] [选项] --all-databases > /备份路径/备份文件名
#mysqldump -u root -p --opt --all-databases > /backup/all.sql
#--opt是mysqldump命令的一个选项,表示使用优化选项进行备份。具体来说,它等价于以下几个选项的组合:
-
--add-drop-table
: 在每个表的创建语句之前添加DROP TABLE IF EXISTS
语句,确保在恢复数据时可以先删除已存在的表。 -
--add-locks
: 在备份期间为每个表添加LOCK TABLES
语句,确保备份的数据一致性。 -
--create-options
: 在备份期间包含表的创建选项,例如表的字符集、存储引擎等。 -
--quick
: 使用快速插入方式,将每个表的数据记录一条 SQL 语句,而不是每行记录生成一条 SQL 语句。 -
--extended-insert
: 使用扩展插入方式,将多个记录组合成一条 INSERT 语句,减少了语句本身的开销。 -
--lock-tables
: 在备份期间锁定所有的表,确保备份的数据一致性。
#备份多个库
mysqldump -u 用户名 -p [密码] [选项] --databases 库名1 [库名2] ... > /备份路径/备份文件名
#mysqldump -uroot -pabc123 --databases school name > /opt/school-name.sql //同时备份school和name库
#备份单个库
mysqldump -u 用户名 -p [密码] [选项] [库名] > /备份路径/备份文件名
#mysqldump -uroot -pabc123 school > /opt/school.sql
1.2.2 备份表
mysqldump -u 用户名 -p [密码] [选项] 数据库名 表名 > /备份路径/备份文件名
#mysqldump -uroot -pabc123 school cd > /backup/school-cd.sql
1.2.3 -F参数和--set-gtid-purged=OFF
不建议使用-F
mysqldump -u username -p -F --databases database1 database2 > backup.sql
使用mysqldump命令备份数据时,如果加上 -F选项,会导致 MySQL Server 刷新所有的日志文件,包括 binlog 日志。这意味着,在备份过程中,发生的所有数据变更都将被记录在 binlog 中。
具体来说,当使用 -F
选项时,MySQL Server 会执行以下操作:
-
执行
FLUSH TABLES WITH READ LOCK
命令,阻塞所有的写操作,确保备份期间不会有新的数据写入。 -
执行
FLUSH LOGS
命令,刷新所有的日志文件,包括 binlog、redo log 和 error log 等。 -
执行
UNLOCK TABLES
命令,释放表锁,允许其他用户进行写操作。
--set-gtid-purged=OFF可以在导出sql中没有指定gtid语句(SET @@GLOBAL.GTID_PURGED=),避免后续恢复binlog中uuid与数据库uuid不一致造成的问题。(查看本机uuid:select @@server_uuid;)
如果备份没用此参数,参考2.3.1也可以解决后续问题
1.2.3 数据恢复
sql备份文件里没有判断库的语句,所以要先创建库,再导入表。
但是备份多个库的时候,备份的sql语句包含了库的判断,所以不用提前创建库
mysql> source /backup/school-cd.sql; //使用绝对路径 '//source命令在mysql库中使用'
或者
mysql -u 用户名 -p [密码] < 表备份脚本的路径
#mysql -u root -p mysql < /backup/school-cd.sql
1.2.4 恢复故障处理
故障1:ERROR 3546 (HY000) at line 26: @@GLOBAL.GTID_PURGED cannot be changed: the added gtid set must not overlap with @@GLOBAL.GTID_EXECUTED
这个错误通常是由于 GTID(全局事务标识)配置不一致导致的。GTID 是用于在主从复制环境中跟踪事务的全局唯一标识符。在进行数据恢复时,MySQL 会检查新的 GTID 集合是否与已经执行的 GTID 集合有重叠。 解决此问题的方法取决于你的具体情况: 如果你在执行备份时使用了 --single-transaction 或 --master-data 选项,那么备份文件中应该包含了 GTID 相关的信息。在恢复数据时,你需要确保 MySQL 实例的 GTID 模式和备份文件中的 GTID 配置一致。 如果你的 MySQL 实例的 GTID 模式为 OFF,则可以在连接 MySQL 后执行 SET GLOBAL GTID_MODE = OFF_PERMISSIVE;,然后再执行恢复命令。 如果你的 MySQL 实例的 GTID 模式为 ON,则可以在连接 MySQL 后执行 SET GLOBAL GTID_MODE = ON_PERMISSIVE;,然后再执行恢复命令。 如果你没有使用 GTID 相关的选项进行备份,而备份文件中引起冲突的是 GTID 相关的 SQL 语句,你可以尝试在执行恢复命令之前先禁用 GTID 功能。 连接到 MySQL 后,执行 SET GLOBAL gtid_mode = OFF; 命令来禁用 GTID 功能。 然后再执行恢复命令:mysql -uroot -pAa.1234567 < /tmp/backupall.sql 请注意,禁用 GTID 功能可能会导致主从复制环境的不一致性。如果你是在主从复制环境中进行数据恢复,请谨慎操作,并在完成恢复后重新启用 GTID 功能以确保数据同步的正确性。
2. 增量备份
增量备份就是备份自上一次备份之后增加或变化的文件或者内容
mysql没有提供直接的增量备份方法,这里就是通过mysql的binlog日志实现增量备份,
当数据库发生变化时,binlog会记录数据库中的所有变化;需要恢复的时候可以根据binlog中的开始位置和结束位置还原本部分操作;结束位置一般是数据被破坏或删除之前的位置。
2.1 确定已开启binlog
[root@localhost ~]# cat /etc/my.cnf log-bin=mysql-bin //开启binlog
server-id=1
#默认保存路径是/usr/local/mysql/data
mysql > show variables like ‘%log_bin%’;
2.2 备份binlog
1.2.3步骤中有描述-F参数,不建议使用。最好找个夜间没有变动的时间进行全量备份和flush logs;
在完全备份后执行flush logs;来生成新binlog文件,这样可以保证新log文件是基于完全备份后的增量数据;
在增量备份时执行flush logs;来生成新binlog文件,这样可以保证备份的旧log文件是完整的增量数据。否则可能备份binlog003后还一直向003追加日志
mysqladmin -u 用户名 -p [密码] flush logs
#flush logs作用是关闭当前使用的binary log,然后打开一个新的binary log文件,文件的序号加1。
cp备份文件
2.3 增量备份恢复
先根据全量备份文件恢复,在根据binlog进行增量恢复
2.3.1 查看binlog文件
- 根据日志来确定恢复的开始位置和结束位置
- 确定日志中gtid和数据库show master status的gtid差异(查看本机uuid:select @@server_uuid;)
注意:若gtid中uuid不一致,正常会导致恢复失败。因为binlog中指定了gtid与本机记录的gtid中uuid不一致,所以执行忽略。
若gtid中事务不一致,当mysql事务大于binlog事务时,会判断部分binlog事务已被执行而跳过造成数据缺失
当mysql事务小于binlog事务时,中间缺失部分有可能造成数据缺失
以上问题可以通过--set-gtid-purged=OFF参数或者reset master解决,根据具体情况分析选择解决方法。
增加参数--set-gtid-purged=OFF,binlog解析的语句中将不再有SET @@SESSION.GTID_NEXT=指定具体事务。
可以让按顺序执行所有语句,根据本机uuid和事务从1开始记录;
并可以忽略binlog事务数和mysql事务数大小对比,执行binlog语句,在Executed_Gtid_Set中对应的uuid事务数记录递增
#将binlog二进制文件转成sql,方便查询具体位置
[root@mysql data]# mysqlbinlog --no-defaults --base64-output=decode-rows -v mysql-bin.000001 > /opt/bak.txt [root@mysql data]# vim /opt/bak.txt
...... BEGIN /*!*/; # at 293 #201224 19:38:38 server id 1 end_log_pos 346 CRC32 0xf7359359 Table_map: `school`.`cd` mapped to number 222 # at 346 #201224 19:38:38 server id 1 end_log_pos 396 CRC32 0xc34a1362 Write_rows: table id 222 flags: STMT_END_F ### INSERT INTO `school`.`cd` ### SET ### @1=3 ### @2='wangwu' ### @3='20' # at 396 #201224 19:38:38 server id 1 end_log_pos 427 CRC32 0xa5b658aa Xid = 173 COMMIT/*!*/; # at 427 #201224 19:39:32 server id 1 end_log_pos 492 CRC32 0x812226d5 Anonymous_GTID last_committed=1 sequence_number=2 rbr_only=yes /*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/; SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/; # at 492 #201224 19:39:32 server id 1 end_log_pos 566 CRC32 0x61231674 Query thread_id=17 exec_time=0 error_code=0 SET TIMESTAMP=1608809972/*!*/; BEGIN /*!*/; # at 566 #201224 19:39:32 server id 1 end_log_pos 619 CRC32 0x7a6e973e Table_map: `school`.`cd` mapped to number 222 # at 619 #201224 19:39:32 server id 1 end_log_pos 671 CRC32 0x24435a14 Delete_rows: table id 222 flags: STMT_END_F ### DELETE FROM `school`.`cd` ### WHERE ### @1=1 ### @2='zhangsan' ### @3='18' # at 671 #201224 19:39:32 server id 1 end_log_pos 702 CRC32 0xc9db2a9b Xid = 174 COMMIT/*!*/; # at 702 #201224 19:40:19 server id 1 end_log_pos 767 CRC32 0x4ae2a49c Anonymous_GTID last_committed=2 sequence_number=3 rbr_only=yes /*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/; SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/; # at 767 #201224 19:40:19 server id 1 end_log_pos 841 CRC32 0xa41b163a Query thread_id=17 exec_time=0 error_code=0 SET TIMESTAMP=1608810019/*!*/; BEGIN /*!*/; # at 841 #201224 19:40:19 server id 1 end_log_pos 894 CRC32 0x2c22cb13 Table_map: `school`.`cd` mapped to number 222 # at 894 #201224 19:40:19 server id 1 end_log_pos 946 CRC32 0xfe387271 Write_rows: table id 222 flags: STMT_END_F ### INSERT INTO `school`.`cd` ### SET ### @1=5 ### @2='zhangliu' ### @3='21' # at 946 #201224 19:40:19 server id 1 end_log_pos 977 CRC32 0x40cd330a Xid = 175 COMMIT/*!*/; # at 977 #201224 19:42:30 server id 1 end_log_pos 1024 CRC32 0x7096e131 Rotate to mysql-bin.000003 pos: 4 SET @@SESSION.GTID_NEXT= 'AUTOMATIC' /* added by mysqlbinlog */ /*!*/; DELIMITER ; # End of log file /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/; /*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/; ......
注意:时间点201224 19:38:38 对应的是 2020-12-24 19:38:38'
此案例误操作时间是201224 19:39:32 delete语句,位置点是at 671 (已标红)
2.3.2 基于时间点的断点恢复
mysqlbinlog --no-defaults --stop-datetime='2020-12-24 19:38:38' /usr/local/mysql/data/mysql-bin.000001 | mysql -u root -pabc123 '//第一个正常操作的结尾时间是'2020-12-24 19:38:38',此处用此时间,表示恢复到此时间的操作'
#mysqlbinlog --no-defaults --skip-gtids --stop-datetime='2020-12-24 19:38:38' /usr/local/mysql/data/mysql-bin.000001 | mysql -u root -pabc123
#--skip-gtids是'开启跳过gtids',效果看2.3.1
mysqlbinlog --no-defaults --start-datetime='2020-12-24 19:40:19' /usr/local/mysql/data/mysql-bin.000002 | mysql -u root -pabc123 '//跳过中间失误操作失误操作后的正常操作的开始时间是'2020-12-24 19:40:19',此处用此时间,表示从此时间恢复到结尾的操作'
mysqlbinlog --no-defaults --skip-gtids --start-datetime='2020-12-24 19:40:19' /usr/local/mysql/data/mysql-bin.000002 | mysql -u root -pabc123
#--skip-gtids是'开启跳过gtids',效果看2.3.1
语句中start-datetime和stop-datetime可以同时指定,如果未指定就是binlog的最开始或最结尾
2.3.3 基于位置点的断点恢复
mysqlbinlog --no-defaults --stop-position='619' /usr/local/mysql/data/mysql-bin.000001 | mysql -u root -pabc123 //这里619对应误操作671的上一个位置点,这里千万不要写671,写了671这个位置,就说明把这个位置的语句执行一遍; #mysqlbinlog --no-defaults --skip-gtids --stop-position='619' /usr/local/mysql/data/mysql-bin.000001 | mysql -u root -pabc123
#--skip-gtids是'开启跳过gtids',效果看2.3.1
mysqlbinlog --no-defaults --skip-gtids --start-position='767' /usr/local/mysql/data/mysql-bin.000001 | mysql -u root -pabc123 //767位置点为误操作的下一个位置点
#mysqlbinlog --no-defaults --start-position='767' /usr/local/mysql/data/mysql-bin.000001 | mysql -u root -pabc123
#--skip-gtids是'开启跳过gtids',效果看2.3.1
或者 mysqlbinlog --no-defaults --skip-gtids --start-position='767' /usr/local/mysql/data/mysql-bin.000001 > 1.sql 后source执行也可以
语句中start-position和stop-position可以同时指定,如果未指定就是binlog的最开始或最结尾
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本