事务是数据库系统区别于文件系统的重要特性之一。
文件系统中,如果正在写入某个文件时,操作系统崩溃,当操作系统恢复后,该文件很可能被损坏。
当然,通过操作系统镜像或checkpoint等技术可以把文件恢复到某个时间。不过要保证两个文件同步,就有点无能为力了。比如需要更新两个文件,当更新完一个文件后,系统重启,而没有完成另一个文件的更新,那么就会有两个不一样的文件。
1.数据库系统引入事务的原因
事务会把数据库系统从一种一致性的状态转换为另一种一致状态。
2.事务的特性
理论上来说,事务有严格的定义,需满足ACID四个特性。
但实际数据库厂商可能为了某些因素考量,没有严格满足事务的四个标准。比如:
(1)MySQL NDB Cluster引擎虽然支持事务,但不满足D的要求。
(2)Oracle默认事务隔离级别为Read Committed,不满足I的要求。可能会带来性能的提升。
(3)MySQL Innodb引擎默认的事务隔离级别为Read Repeatable。完全遵循和满足ACID特性。
2.1.原子性(Atomicity)
原子性表示整个事务都是一个整体,事务中所有的操作要么全部成功,要么全部失败。
如果事务中所有操作都是只读的,保持原子性非常简单,一旦发生错误,重试或者返回错误码即可。并不会对系统的状态产生影响。
如果事务中有部分操作是可写的,比如insert、update或delete,这些操作会引起系统状态的变化。如果操作失败,则需要进行特殊操作才能回到事务初始时状态。
2.2.一致性(Consistency)
一致性是指数据库状态从一种一致状态转变为下一种一致状态。在事务开始前和事务结束后,数据库的完整性约束没有被破坏。
例如,表的name字段具有唯一约束。如果一个事务对该表的name字段进行修改,事务提交或者回滚后,name字段不满足唯一约束,就表示数据库进入了不一致状态。
2.3.隔离性(Isolation)
事务的隔离性要求每个读写事务的对象对其他事务的操作对象能相互分离,即该事务提交前,其他事务都不可见,通常通过锁来实现。
2.4.持久性(Durability)
持久性表示事务一旦提交,其结果就是永久性的,即使发生宕机等故障,也能恢复如初。
但如果不是数据库本身发生的故障,而是一些外部原因,比如RAID卡损坏、自然灾害等原因,提交的数据可能会丢失。
所以,持久性保证事务系统的高可靠性(High Reliability),而不是高可用性(High Availability)。对于高可用性,事务本身不能实现,需要一些系统的共同配合才能实现。
3.事务的分类
事务可分为以下类型
3.1.扁平事务
Flat Transaction,最简单的一种事务。如下图所示:
扁平事务中,所有操作都都处于同一层次,由BEGIN WORK开始,COMMIT WORK或ROLLBACK WORK。
3.1.1.扁平事务的优点
扁平事务简单,是生产环境中使用最为频繁的。所以每个数据库系统都实现了对扁平事务的支持。
3.1.2.扁平事务的限制
不能commit或rollback事务中的某一部分,或者分几个步骤提交。
比如,用户在某个旅游网站制定旅游计划,从深圳到巴塞罗那,由于没有直达的行程,需要在整个行程事务中分为以下三个部分:
(work1)从深圳到香港
(work2)从香港到马德里
(work3)从马德里到巴塞罗那
当用户到马德里后,由于某些原因,无法执行work3操作,如果按照扁平事务的特点,就需要回滚work2和work1,回到深圳,代价有点大。如果支持有计划的回滚,那就不需要终止整个事务,所以带保存点的扁平事务出现了。
3.2.带保存点的扁平事务
Flat Transaction with Savepoint,如下图所示:
除了支持扁平事务支持的操作外,允许在事务执行过程中rollback到同一事务的较早一个状态。
保存点用来通知系统记住当前事务的状态,以便之后发生错误时,事务能回滚到当前的状态。
保存点在事务内部是递增的。
3.2.1.带保存点的扁平事务的限制
带保存点的扁平事务,当系统崩溃时,所有的保存点都将消失,因为其保存点是易丢失的(volatile),而非持久的(persistent)。这也意味着进行恢复时,事务需要从开始处重新执行,而不能从最近的一个保存点继续执行。
3.3.链事务
Chained Transaction,可以视为保存点模式的变种,可以解决带保存点扁平事务的限制问题。
链事务的核心思想:在提交一个事务时,释放不需要的数据对象,将必要的处理上下文隐式地传递给下一个要开始的事务。注意,事务提交操作和下一个事务开始操作将合并为一个原子操作。这意味着下一个事务将看到上一个事务的结果,就好像在一个事务中进行一样。
3.3.1.链事务 vs 带保存点的扁平事务
(1)回滚操作的不同
带保存点的扁平事务能回滚到任意正确的保存点。
链事务的回滚仅局限于当前事务。
(2)锁的处理不同
链事务在commit之后即释放了当前事务所持有的锁。
带有保存点的扁平事务不影响迄今为止所持有的锁。
3.4.嵌套事务
Nested Transaction,是一个层次结构框架,由一个顶层事务(top-level transaction)控制各个层次的事务。顶层事务之下的嵌套事务称为子事务(subtransaction),并控制每一个局部的变更。
嵌套事务由若干事务组成的一棵树,子树既可以是嵌套事务,也可以是扁平事务。
处在叶节点的事务是扁平事务,每个子事务从根到叶子节点的距离可以是不同的。
位于根节点的事务为顶层事务,其他事务称为子事务。
子事务既可以提交也可以回滚,但是他的提交操作并不马上生效,除非其父事务已提交。因此,任何子事务都在顶层事务提交后才能真正的提交。
树中任意一个事务的回滚会引起他的所有子事务一起回滚,故子事务仅保留ACI特性,不具备D特性。
3.5.分布式事务
Distributed Transaction.
这是一个在分布式环境下运行的扁平事务,需要根据数据所在位置访问网络中的不同节点。
下面是一个经典的分布式事务案例。
ATM、Bank 1、Bank 2分别属于三个不同的系统,也就是三个不同的节点,如果要转账成功,则此三个节点都要成功,任何一个节点失败,所有节点都需要进行回滚操作。