第 3 章 · 数据库第 3 页,共 4 页
一件事要改两处,改到一半断电了怎么办?
读者收藏一道菜,数据库要改两处:记下这条收藏,再把这道菜的收藏数加一。这一页让断电发生在两步之间,比较用了事务和没用事务时,重新开机以后两处还对不对得上。
为什么需要
第 1 页的菜谱表里有一列收藏数:番茄炒蛋有 41 人收藏。里另有一张收藏表,每一行写着谁收藏了哪道菜,第 1024 号的收藏记录也是 41 行。收藏数本可以每次去收藏表里数,但菜谱每被打开一次就要数一遍,所以菜谱表里另存一个现成的数,打开时直接读。两处说的是同一件事,必须对得上。
你点一下收藏,数据库要做两步:第 1 步,在收藏表里加一行;第 2 步,把番茄炒蛋的收藏数从 41 改成 42。要是第 1 步做完,第 2 步还没做,机器就断了电呢?重新开机以后,收藏记录有 42 行,收藏数却还是 41。
怎样做
办法是把这两步绑成一组,要么全做,要么全不做,不会停在中间,这叫(transaction)。你平时说的事务,指要办的事情,也有人会想到买卖的交易;这里是数据库的术语。
程序先告诉数据库「开始」,再做这两步。两步都做完,就(commit):两处改动一起生效,数据库并保证它们断电也不丢。提交之前出了错,或者程序决定不做了,就(rollback),撤销这个事务开始以来做过的所有改动;没来得及提交就断了电,重新开机以后,数据库同样把这半截改动作废。第 14 章讲发布新版本时也说回滚,那里指把程序换回上一个版本,与这里不是一回事。
在下图里,让断电发生在第 1 步做完以后,比一比用事务和不用事务时,重新开机后两张卡片对不对得上。
做到一半:两步之间断电,两处还对得上吗
先看这里先选「不用事务」,按「下一步」一直播到重新开机以后,看两张卡片;再换成「用事务」播一遍。
收藏记录
收藏表里第 1024 号的行数41 行- 第 1 步:收藏表加一行未做
- 第 2 步:收藏数加一未做
收藏数
菜谱表里第 1024 号的收藏数41做到一半的示意图:左边一张卡片是收藏表里第 1024 号的收藏记录有几行,右边一张是菜谱表里它的收藏数,中间是两个步骤和断电的时刻;用事务时,第 1 步之前有「开始」,第 2 步之后有「提交」。每一步的变化写在图下的说明里。
还没开始。按「下一步」或「自动播放」。
| 第 1 步做完以后断电 | 不断电 | |
|---|---|---|
| 不用事务 | — | — |
| 用事务 | — | — |
收藏记录和收藏数都是为演示虚构的。「断电」指数据库所在的机器在两步之间断电,重新开机以后再看两张卡片。
事务里的几步是一个分不开的整体,这叫(atomicity);原子说的是不可分割,与大小、快慢无关。提交以后改动不丢,就是第 1 页讲的。事务应当做到的几项保证常合称 ,取四项保证的英文首字母,原子性(A)和持久性(D)是其中两项。
代价是什么
代价是等:提交要等改动真正写进硬盘,才回报成功。有的数据库可以设成先回报成功、稍后再写硬盘,这样快一些,但机器出了故障,最近的几笔改动就可能丢掉。
还要分清是哪一种故障。只是数据库程序崩溃时,机器一直开着:它已经交给的数据,通常由操作系统接着写进硬盘;还留在数据库自己内存里的改动,用了更快的设置时就会丢。整台机器断电时,只有已经写进硬盘的才在。上图演示的是后一种。
资料来源
以下资料均于 2026-10-23 访问。