查看错误日志和二进制日志,删除旧的二进制日志,最后用完整备份加二进制日志,把误删的数据还原到出错之前。
MySQL 8.0 和 MySQL Workbench。备份、还原的命令在 Windows 的命令提示符中执行,查看结果的语句在 Workbench 中执行。
按 Win+R,输入 cmd,按 Enter 键。不要用 PowerShell,它不支持 < 还原。
命令一次复制一行,出现 Enter password: 时输入 root 的密码,输入时屏幕上不显示。
与实验一相同的脚本,执行后 teaching 库回到初始状态。
-- 第 10 章实验数据:重建教材 teaching 库,删除本章实验建的库 -- 在 Workbench 中用 root 连接整段执行。四次实验共用,想从头再做时重新执行即可。 DROP DATABASE IF EXISTS teaching_copy; DROP DATABASE IF EXISTS teaching_empty; DROP DATABASE IF EXISTS teaching; CREATE DATABASE teaching DEFAULT CHARACTER SET utf8mb4; USE teaching; -- 课程表 CREATE TABLE c ( cno CHAR(4) NOT NULL, cn VARCHAR(30) NOT NULL, ct INT, PRIMARY KEY (cno) ); -- 学生表 CREATE TABLE s ( sno CHAR(4) NOT NULL, sn VARCHAR(20) NOT NULL, sex CHAR(2), age INT, maj VARCHAR(30), dept VARCHAR(30), PRIMARY KEY (sno) ); -- 教师表 CREATE TABLE t ( tno CHAR(4) NOT NULL, tn VARCHAR(20) NOT NULL, sex CHAR(2), age INT, prof VARCHAR(20), maj VARCHAR(30), dept VARCHAR(30), sal DECIMAL(8,2), PRIMARY KEY (tno) ); -- 选课表 CREATE TABLE sc ( sno CHAR(4) NOT NULL, cno CHAR(4) NOT NULL, score DECIMAL(5,2), PRIMARY KEY (sno, cno), FOREIGN KEY (sno) REFERENCES s (sno), FOREIGN KEY (cno) REFERENCES c (cno) ); -- 授课表 CREATE TABLE tc ( tno CHAR(4) NOT NULL, cno CHAR(4) NOT NULL, tcdate DATE, PRIMARY KEY (tno, cno), FOREIGN KEY (tno) REFERENCES t (tno), FOREIGN KEY (cno) REFERENCES c (cno) ); INSERT INTO c VALUES ('c1','Java程序设计',40), ('c2','程序设计基础',48), ('c3','线性代数',48), ('c4','数据结构',64), ('c5','数据库系统',56), ('c6','数据挖掘',32), ('c7','高等数学',60), ('c8','控制理论',32); INSERT INTO s VALUES ('s1','王彤','女',18,'计算机','信息学院'), ('s2','苏乐','男',20,'信息','信息学院'), ('s3','林欣怡','女',19,'信息','信息学院'), ('s4','陶然','男',19,'自动化','工学院'), ('s5','魏立','男',17,'数学','理学院'), ('s6','何欣荣','女',21,'计算机','信息学院'), ('s7','赵琳琳','女',19,'数学','理学院'), ('s8','李轩','男',18,'自动化','工学院'); INSERT INTO t VALUES ('t1','刘杨','男',38,'教授','计算机','信息学院',3800.00), ('t2','石丽','女',28,'讲师','计算机','信息学院',2800.00), ('t3','顾伟','男',35,'副教授','计算机','信息学院',3200.00), ('t4','赵礼','男',45,'教授','自动化','工学院',4267.90), ('t5','赵希希','女',33,'副教授','数学','理学院',3332.67), ('t6','张刚','男',30,'讲师','计算机','工学院',2600.00); INSERT INTO sc VALUES ('s1','c1',90.50), ('s1','c2',88.00), ('s2','c4',70.00), ('s2','c5',57.00), ('s2','c6',81.50), ('s2','c7',NULL), ('s3','c1',75.00), ('s3','c2',76.50), ('s3','c4',85.00), ('s4','c1',93.00), ('s4','c2',82.00), ('s4','c6',NULL), ('s4','c7',68.00), ('s5','c2',79.00), ('s5','c7',84.00), ('s7','c3',77.00), ('s7','c5',62.00), ('s7','c7',100.00), ('s8','c2',66.00), ('s8','c3',96.00); INSERT INTO tc VALUES ('t1','c1','2021-09-03'), ('t1','c2','2021-09-04'), ('t2','c5','2021-03-06'), ('t2','c6','2021-09-06'), ('t3','c2','2021-03-08'), ('t3','c4','2021-09-08'), ('t4','c3','2021-03-10'), ('t5','c7','2021-09-12'), ('t5','c8','2021-03-15'); SHOW TABLES;
-- 错误日志的文件名,开头的点号表示数据目录 SHOW VARIABLES LIKE 'log_error'; SHOW VARIABLES LIKE 'datadir'; -- 最近的 10 条错误日志 SELECT LOGGED, PRIO, DATA FROM performance_schema.error_log ORDER BY LOGGED DESC LIMIT 10;
| log_error | 错误日志的文件名,默认是 主机名.err |
| datadir | 数据目录,错误日志默认放在这里 |
| performance_schema.error_log | MySQL 8.0 把最近的错误日志放在这张表中,可以直接查询 |
| PRIO | 级别:System 系统信息,Error 错误,Warning 警告,Note 提示 |
SHOW VARIABLES LIKE 'log_bin%'; SHOW BINARY LOGS; SHOW MASTER STATUS; -- 关闭当前的二进制日志文件,换一个新文件 FLUSH BINARY LOGS; SHOW BINARY LOGS;
| log_bin | ON 表示二进制日志已经打开,MySQL 8.0 默认打开 |
| log_bin_basename | 日志文件的位置和名称,文件名后面加编号 |
| SHOW BINARY LOGS | 列出全部日志文件和每个文件的大小 |
| SHOW MASTER STATUS | File 是正在写的文件,Position 是写到的位置 |
| FLUSH BINARY LOGS | 换一个新的日志文件,编号加 1 |
PURGE 语句中的文件名要换成本机第一句结果中最后一行的文件名,也就是正在写的文件。
SHOW BINARY LOGS; -- 文件名换成上一句结果中最后一行的文件名 PURGE BINARY LOGS TO 'DESKTOP-TKC62RP-bin.000003'; SHOW BINARY LOGS; -- 删除全部日志,从 000001 重新编号 RESET MASTER; SHOW BINARY LOGS;
| PURGE BINARY LOGS TO | 删除编号比它小的全部文件,它本身保留。PURGE MASTER LOGS 作用相同 |
| 文件名写错 | 报错 1373,在日志索引中找不到这个文件 |
| RESET MASTER | 删除全部日志,新文件从 000001 开始。MySQL 8.4 中改为 RESET BINARY LOGS AND GTIDS |
USE teaching; SELECT * FROM s WHERE sno = 's1'; UPDATE s SET age = 19 WHERE sno = 's1'; -- 不写 IN 文件名时,显示第一个日志文件,现在只有 000001 SHOW BINLOG EVENTS;
mysqlbinlog -R -u root -p -v DESKTOP-TKC62RP-bin.000001 > binlog1.txt notepad binlog1.txt
| SHOW BINLOG EVENTS | 列出日志中的事件,Pos 是事件的开始位置,Info 是事件的内容 |
| Update_rows | UPDATE 修改了一行。前后的 BEGIN 和 COMMIT 表示一个事务 |
| mysqlbinlog -R | 通过服务器读取日志,只写文件名,不用管文件在哪个文件夹 |
| -v | 把行的修改显示成以 ### 开头的类似 SQL 的注释 |
RESET MASTER;
mysqldump -u root -p --databases teaching > teaching_full.sql
USE teaching; INSERT INTO s VALUES ('s9','周末','男',20,'计算机','信息学院'); UPDATE s SET age = 21 WHERE sno = 's2'; -- 误删了选课表 DROP TABLE sc; SELECT * FROM s;
| RESET MASTER | 实验中为了查找方便才清空日志。实际工作中备份时执行 FLUSH LOGS,换一个新的日志文件 |
| teaching_full.sql | 完整备份,只包含备份那一刻的数据 |
| INSERT、UPDATE | 备份以后的修改,备份文件中没有,只记在二进制日志中 |
| DROP TABLE sc | 模拟误操作 |
第 3 步的 --stop-position 换成本机查到的 Pos,文件名也换成本机的。
mysql -u root -p < teaching_full.sql
SELECT COUNT(*) FROM teaching.sc; SELECT * FROM teaching.s WHERE sno IN ('s2', 's9'); -- 找到 Info 为 DROP TABLE 的一行,记下它的 Pos SHOW BINLOG EVENTS;
mysqlbinlog -R -u root -p --stop-position=958 DESKTOP-TKC62RP-bin.000001 > redo.sql mysql -u root -p < redo.sql
SELECT COUNT(*) FROM teaching.sc; SELECT * FROM teaching.s WHERE sno IN ('s2', 's9');
| mysql … < teaching_full.sql | 还原到备份那一刻:sc 回来了,但 s9 和 s2 的修改也没有了 |
| --stop-position=958 | 读到这个位置就停止,DROP TABLE 从这里开始,不会被重放 |
| > redo.sql | 把要重放的内容先存成文件,可以用记事本打开看一看 |
| mysql … < redo.sql | 执行日志中备份以后的修改 |