seegongsik
数据

什么是数据库事务

假设你要给朋友转一百块钱。得从你的余额里扣掉一百块,再往朋友的余额里加上一百块。可要是扣完了,正要加的时候突然断电呢?钱已经从你的账户里出去了,朋友却一分也没收到。为了防止这种事故,把几项修改捆成一个整体,要么全部完成,要么全部不做,这个办法就叫事务。

01

转账是扣和加凑成的一对

上一课,我们把表拆开,让每条信息只放在一处。即便如此,有些事也不是改一处就能完成的,转账就是这样:要从你的余额里扣钱,再往收款人的余额里加上同样多的钱。
这两步是拆不开的一对。只做成一步,钱不是凭空消失,就是凭空多出来。下面把两项修改分开做做看。

我的余额30
朋友余额10
两者之和40
把两个按钮分开点

分别点扣和加。只点一个,两个余额的总和就会变:钱要么没了,要么凭空多出来。

只点扣,你的钱就没了;只点加,就凭空多出钱来。不管哪种,两个余额的总和都跟开始时不一样了。转账只是把钱挪个地方,总和本该不变。
危险就在扣和加之间那一小段空隙。要是这时断了电,或者程序停了,账本就会对不上,而且一直这样留着。所以需要一个办法,把这两项修改绑在一起。

02

要么全部完成,要么全部不做

办法很简单:把扣和加捆成一个整体,这个整体就叫事务。整体里的修改,一律先当作临时的。
全部准备好了,就确定下来,一次性真正生效;哪怕有一项不成,就全部取消。确定叫提交,取消并撤回叫回滚。这样一来,就不会出现只生效一半的状态,别人也看不到中间状态。这种性质叫原子性,意思是它是一个不能再拆分的整体。

一个整体(事务)
放入扣
放入加
我的余额30
朋友余额10
把两次改动放进整体

把两项修改放进一个整体。两项都放进去才能确定,一取消,放进去的两项就都没了。

一确定,两个余额一起变,总和不变;一取消,两项都干干净净地没了。不管哪种,账本都对得上。只是当成整体来处理,危险的空隙就没了。
可要是在整体里干到一半,真的断电了,会怎样?那些临时的修改又怎么处理?

03

断了也整个退回去

数据库在修改之前,会先把要改什么、怎么改写进一种叫日志的记录里,还会留下能回到开始前状态的信息。
所以,就算中途断电,重新启动后读一读日志,就能找出没做完的整体。然后它不会留下一半,而是把这个整体整个退回到开始前的状态。反过来,已经提交的整体,断电后也照样保留着。提交的结果不会丢失,这种性质叫持久性。

开始前的状态(另外记下)30 / 10
我的余额30
朋友余额10
先走一步,再制造一次断开

先走一步,再点电源断开。它不会只留下一半,而是整个退回到另外记下的开始前状态。

断了电,账本却安然无恙。不是只扣了钱的一团糟,而是干干净净地回到了开始前。这就是回滚。
失败了也不留痕迹,从头再来就行。不论转账前还是转账后,账本的规则都得到遵守,比如两个余额的总和不变。这叫一致性。那么,要是好几个人同时想改同一笔余额,又会怎样?

04

同时来了,也轮着处理

回想一下操作系统那部分讲过的竞争条件:两方同时碰同一份资源,结果就乱了。余额也一样。
两个人同时读同一笔余额,各自把加好的值写回去,后写的人就会把前一个人的结果覆盖掉,一个人的修改就整个没了。这叫丢失更新。所以数据库会用锁之类的机制,让修改同一行的事务一个一个轮着处理。

人 X (+5)+5
人 Y (+8)+8
同一笔余额100
同时发出,一方覆盖另一方

同时把两个人发出去。不管的话,后写的一方会覆盖,一方的改动就没了;轮着挡住,两样都会加上。

不管的话,一方的改动没了;轮着处理,两样都生效了。就算同时到来,也让它们先排一会儿队,一个整体做完,再接下一个。
像这样把同时运行的事务隔开,不让它们看到彼此的中间状态,这种性质叫隔离性。不过,所有事务都严格排队会很慢,所以实际的数据库会让你选择隔离到什么程度。

05

小结

归纳起来是这样:把必须一起变的修改捆成一个整体,要么全部完成,要么全部不做。中途断了,就看日志把一切整个退回到开始前;已经提交的结果,断电也不会丢。
好几个事务同时想改同一处时,就让它们轮着排队,挡住覆盖。原子性、一致性、隔离性、持久性,取英文首字母合称 ACID,这四个承诺就是事务。

依次点四个要点
从上往下依次点下面的要点

依次点要点回顾一下。(转账是一对 → 要么全做要么全不做 → 出岔就回滚 → 同时也不乱)

现在你知道了安全修改数据的承诺。钱凭空消失的空隙,断电只留下一半的事故,同时修改互相覆盖的混乱,靠“一个整体”这个想法都能防住。
学会了安全地改,接下来是快速地读。与其一次次跑到数据库去取同样的数据,不如在近处放一份副本,下一课讲缓存时会说明这个办法。

一句话总结事务就是把必须一起变的几项修改当作一个整体来处理,要么全部完成,要么全部不做。像转账这样扣和加成对的时候,两项都准备好了才提交,有一项不成就全部取消。就算中途断电,数据库也会靠事先写下的日志找出没做完的事务,把它整个退回到开始前的状态,这叫回滚。已经提交的结果,断电后也会保留。好几个人同时想改同一笔余额时,就一个一个轮着处理,不让彼此覆盖。原子性、一致性、隔离性、持久性合称 ACID,这四项就是事务的承诺。
← 数据
如果有帮助,请支持我们