事务救不了「改错了」:commit 之后就回不去了。 备份是唯一能在删错之后救你的东西。
逻辑备份导成 SQL(能看懂、能跨版本、慢);物理备份拷文件(快、绑版本)。
常规做法是「物理做日常、逻辑做归档」。
备份的三条铁律:要能恢复而且演练过、要放在另一台机器、要定期且留多份。
第 15 章讲事务, 这一章讲它的「补集」—— 事务防「改一半」,备份防「改错了」。 这两件事的分工,很多人在出事之前没分清。 这一章没有复杂语法,全是「怎么做才不出事」的判断。 它比第 12 章的索引更不容易写错,但更容易被忽略。
一、先说清楚:事务救不了你
Demo 里一句 delete 删掉三个学生、然后 commit,
再 rollback 已经没用了——查出来还是两行。
第 15 章说过:commit 之后就回不去了。 日志是用来「崩溃恢复」的,不是用来「人反悔」的。
所以「删错了怎么办」这个问题,两个答案要分清:事务的答案是「没法办」(没提交才有救);
备份的答案是「把昨天那份拿回来」。
这就是为什么「有事务了还要备份」——它们防的是两种完全不同的错。
二、逻辑备份和物理备份
逻辑备份:把数据导成「一串 SQL 语句」,MySQL 的 mysqldump 就是干这个的。
物理备份:直接把数据文件拷走,不管里面是什么格式。 本沙箱的「备份」就是拷 .db 文件。
逻辑备份的好处是「能看懂、能改、能跨版本、能只挑一部分」——
导出来是个文本文件,grep 一下就知道有没有你要的数据;
坏处是「慢」,大库导一次要几小时,还原更慢(要重新执行几百万条 insert)。
物理备份的好处是「快」(拷文件而已),
坏处是「绑版本、绑平台」——
MySQL 5.7 的数据文件不能直接给 8.0 用,Windows 上的也不能直接给 Linux 用。
所以常规做法是「物理做日常、逻辑做归档」:
每天拷文件(快、能快速恢复),每个月导一次 SQL(留个能跨版本的底)。
两种都做,成本很低,收益互补。
三、全量备份和增量备份
全量:每次备份整份数据。 简单、恢复快(只要一份),但占空间、耗时间。
增量:
只备份「上次备份之后变化的部分」。 省空间、快,但恢复麻烦——
要先恢复全量,再按顺序叠每个增量,中间缺一个就恢复不出来。
MySQL 的增量靠 binlog(二进制日志):它记着每一条改动数据的语句,
所以「恢复到今天下午三点」这种需求,靠的是「全量 + 重放 binlog 到那个时刻」。
这是误删数据最常见的救命手段。
本沙箱没有 binlog,
只有「拷文件」和「导 SQL」两招。 所以这里的「增量」只能自己想办法:
每天导一份、按日期存着,要回哪一天就用哪一份。 粗糙,但够用。
四、备份的三条铁律
第一条:备份要能恢复,而且你演练过。 「备份文件存在」不等于「能恢复」—— 文件可能是 0 字节的、可能是半截的、可能权限不对读不了。 所以定期要真恢复一次到测试库,看数据对不对。 没演练过的备份,等于没有备份。 第二条:备份要在另一台机器上。 和原库放同一块硬盘,硬盘坏了两个一起没; 放同一台机器,机器被勒索病毒加密了,备份一起被加密。 这一条每年都有人用血泪重新发现一次。 第三条:备份要定期、要留多份。 每天一份、留三十天, 这样「上周三误删了、今天才发现」还有救。 只留最新一份的话,错误数据会把好数据覆盖掉—— 等你发现时,好数据已经不在任何一份备份里了。
五、动手 Demo:先看「事务救不了你」这件事是真的
Demo 就一段:插五个学生、删掉一半、commit、再 rollback,看数据能不能回来。
这段的意义是「破一个幻觉」——很多人以为「数据库有日志,随时能回滚」,这一段就是反例。
import os
import sqlite3
import tempfile
db = os.path.join(tempfile.gettempdir(), "school.db")
c = sqlite3.connect(db)
c.executescript("""
CREATE TABLE students (id INTEGER PRIMARY KEY, name TEXT,
class_id INTEGER);
INSERT INTO students VALUES (1, '张伟', 1), (2, '李娜', 1),
(3, '王强', 2), (4, '赵敏', 2),
(5, '孙悦', 1);
""")
c.commit()
print("原来", c.execute("SELECT COUNT(*) FROM students").fetchone())
# 一句 delete 删掉一半,然后提交——这时候 rollback 已经没用了
c.execute("DELETE FROM students WHERE class_id = 1")
c.commit()
print("删完", c.execute("SELECT COUNT(*) FROM students").fetchone())
# rollback 救不回来,因为已经提交了
c.rollback()
print("rollback 之后", c.execute("SELECT COUNT(*) FROM students").fetchone())
实跑输出:
--------------------------------------------------------------------
第七十八课:数据备份——唯一能在「删错了」之后救你的东西
--------------------------------------------------------------------
先说清楚:事务救不了你
SQL> SELECT COUNT(*) AS 学生数 FROM students
学生数
-------
5
(1 行)
SQL> DELETE FROM students WHERE class_id = 1
影响 3 行
SQL> SELECT COUNT(*) AS 学生数 FROM students
学生数
-------
2
(1 行)
**一句 `delete` 删掉了三个学生,然后 `commit` 了。** **这时候 `rollback` 已经没用了**——
**第 15 章说过:提交之后就回不去了。**
**所以「删错了怎么办」这个问题,事务的答案是「没法办」,备份的答案是「把昨天那份拿回来」。**
**这两件事的分工要分清**:**事务防「改一半」,备份防「改错了」。**
逻辑备份和物理备份
**逻辑备份**:**把数据导成「一串 SQL 语句」**,
**比如一堆 `insert`。** **MySQL 的 `mysqldump` 就是干这个的。**
**物理备份**:**直接把数据文件拷走**,
**不管里面是什么格式。** **本沙箱的「备份」就是拷 `.db` 文件,属于物理备份。**
**两者的取舍很清楚**:
**逻辑备份的好处是「能看懂、能改、能跨版本、能只挑一部分」**——
**导出来是个文本文件,`grep` 一下就知道有没有你要的数据**;
**坏处是「慢」**,**大库导一次要几小时,还原更慢(要重新执行几百万条 `insert`)。**
**物理备份的好处是「快」**(拷文件而已),
**坏处是「绑版本、绑平台」**——
**MySQL 5.7 的数据文件不能直接给 8.0 用,Windows 上的也不能直接给 Linux 用。**
**所以常规做法是「物理备份做日常、逻辑备份做归档」**:
**每天拷文件(快、能快速恢复),每个月导一次 SQL(留个能跨版本的底)。**
全量备份和增量备份
**全量**:**每次备份整份数据。** **简单、恢复快(只要一份),但占空间、耗时间。**
**增量**:
**只备份「上次备份之后变化的部分」。** **省空间、快,但恢复麻烦**——
**要先恢复全量,再按顺序把每个增量叠上去,中间缺一个就恢复不出来。**
**MySQL 的增量靠 `binlog`**(二进制日志):**它记着每一条改动数据的语句**,
**所以「恢复到今天下午三点」这种需求,靠的是「全量 + 重放 binlog 到那个时刻」。**
**这也是「误删数据」最常见的救命手段。**
**本沙箱没有 binlog**,**只有「拷文件」和「导 SQL」两招**。
**所以这里的「增量」只能自己想办法**:
**比如每天导一份、按日期存着,要回哪一天就用哪一份。** **粗糙,但够用。**
备份的三条铁律
**第一条:备份要能恢复,而且你演练过。** **「备份文件存在」不等于「能恢复」**——
**文件可能是 0 字节的、可能是半截的、可能权限不对读不了。**
**所以定期要真恢复一次到测试库,看数据对不对。** **没演练过的备份,等于没有备份。**
**第二条:备份要在另一台机器上。** **备份和原库放在同一块硬盘上,硬盘坏了两个一起没。**
**放在同一台机器上,机器被勒索病毒加密了,备份一起被加密。**
**这一条每年都有人用血泪重新发现一次。**
**第三条:备份要定期、要留多份。** **每天一份、留三十天**,
**这样「上周三误删了、今天才发现」还有救。** **只留最新一份的话,错误数据会把好数据覆盖掉**——
**等你发现时,好数据已经不在任何一份备份里了。**
原来 5 行,删完 2 行。
rollback() 之后还是 2 行——因为那些改动已经 commit 过了,回滚没有东西可回。
这就是「事务不是后悔药」的现场证明。
30 秒实验
- 把
c.commit()挪到rollback()之后再试一次,结果会怎样? - 为什么「物理备份能快速恢复」但「不能跨版本」?
- 只留最新一份备份,什么情况下会「连备份一起坏掉」?
常见误区
- 以为有事务就不用备份。
commit之后回不去,改错了只能靠备份。 - 备份和原库放在同一台机器。 硬盘坏、勒索病毒都会一起带走。
- 只留最新一份备份。 错误数据会把好数据覆盖掉,发现时就晚了。
自测三问(点开对答案)
1. 事务和备份分别防哪种错? —— 事务防「改一半」(原子性),备份防「改错了」(已提交的误操作)。两者不互相替代。 2. 逻辑备份和物理备份各适合什么场景? —— 逻辑备份适合长期归档和跨版本迁移(能看懂、能改、慢); 物理备份适合日常快速备份与恢复(快、绑版本平台)。 3. 「没演练过的备份等于没有备份」怎么理解? —— 备份文件可能 0 字节、半截、权限不对读不了。只有真恢复一次到测试库、数据对得上,才算有备份。知道备份是怎么回事了,下一篇动手:17.2 数据库的备份与还原。
- ☐ (本篇完,下一篇 17.2 数据库的备份与还原)