事务是数据库系统中的重要概念,了解这一律念是以正确的方式开发和数据库交互的应用程序的前提。可是不少同窗对于事务的认识相对片面和肤浅,仅仅把它等同于ACID,不了解数据库系统引入事务的真正动机,ACID对于事务意味着什么以及最重要的:数据库系统是如何保证事务的ACID特性的?java
转帐是生活中常见的操做,好比从A帐户转帐100元到B帐号。站在用户角度而言,这是一个逻辑上的单一操做,然而在数据库系统中,至少会分红两个步骤来完成:mysql
在这个过程当中可能会出现如下问题:sql
为了便于解决这些问题,须要引入数据库事务的概念。数据库
定义:数据库事务是构成单一逻辑工做单元的操做集合
一个典型的数据库事务以下所示并发
BEGIN TRANSACTION //事务开始 SQL1 SQL2 COMMIT/ROLLBACK //事务提交或回滚
关于事务的定义有几点须要解释下:mvc
对于上面的转帐例子,能够将转帐相关的全部操做包含在一个事务中ide
BEGIN TRANSACTION A帐户减小100元 B帐户增长100元 COMMIT
事务使系统可以更方便的进行故障恢复以及并发控制,从而保证数据库状态的一致性。性能
原子性(Atomicity):事务中的全部操做做为一个总体像原子同样不可分割,要么所有成功,要么所有失败。3d
一致性(Consistency):事务的执行结果必须使数据库从一个一致性状态到另外一个一致性状态。一致性状态是指:1.系统的状态知足数据的完整性约束(主码,参照完整性,check约束等) 2.系统的状态反应数据库本应描述的现实世界的真实状态,好比转帐先后两个帐户的金额总和应该保持不变。日志
隔离性(Isolation):并发执行的事务不会相互影响,其对数据库的影响和它们串行执行时同样。好比多个用户同时往一个帐户转帐,最后帐户的结果应该和他们按前后次序转帐的结果同样。
持久性(Durability):事务一旦提交,其对数据库的更新就是持久的。任何事务或系统故障都不会致使数据丢失。
在事务的ACID特性中,C即一致性是事务的根本追求,而对数据一致性的破坏主要来自两个方面
数据库系统是经过并发控制技术和日志恢复技术来避免这种状况发生的。
并发控制技术保证了事务的隔离性,使数据库的一致性状态不会由于并发执行的操做被破坏。
日志恢复技术保证了事务的原子性,使一致性状态不会因事务或系统故障被破坏。同时使已提交的对数据库的修改不会因系统崩溃而丢失,保证了事务的持久性。
在讲解并发控制技术前,先简单介绍下数据库常见的并发异常。
在事务1对数据A的回滚,致使事务2对A的已提交修改也被回滚了。
事务1和事务2读取A的值都为10,事务2先将A加上10并提交修改,以后事务2将A减小10并提交修改,A的值最后为,致使事务2对A的修改好像丢失了同样
在事务1对A的处理过程当中,事务2读取了A的值,但以后事务1回滚,致使事务2读取的A是未提交的脏数据。
因为事务2对A的已提交修改,事务1先后两次读取的结果不一致。
事务1查询A5的数据,因为事务2插入了一条A=4的数据,致使事务1两次查询获得的结果不同
事务的隔离级别越低,可能出现的并发异常越多,可是一般而言系统能提供的并发能力越强。
不一样的隔离级别与可能的并发异常的对应状况以下表所示,有一点须要强调,这种对应关系只是理论上的,对于特定的数据库实现不必定准确,好比mysql
的Innodb存储引擎经过Next-Key Locking技术在可重复读级别就消除了幻读的可能。
全部事务隔离级别都不容许出现脏写,而串行化能够避免全部可能出现的并发异常,可是会极大的下降系统的并发处理能力。
并发控制技术是实现事务隔离性以及不一样隔离级别的关键,实现方式有不少,按照其对可能冲突的操做采起的不一样策略能够分为乐观并发控制和悲观并发控制两大类。
核心思想:对于并发可能冲突的操做,好比读-写,写-读,写-写,经过锁使它们互斥执行。
锁一般分为共享锁和排他锁两种类型
基于锁的并发控制流程:
可能出现的问题:
对于可能发生冲突的并发操做,锁使它们由并行变为串行执行,是一种悲观的并发控制。
核心思想:对于并发可能冲突的操做,基于时间戳排序规则选定某事务继续执行,其余事务回滚。
系统会在每一个事务开始时赋予其一个时间戳,这个时间戳能够是系统时钟也能够是一个不断累加的计数器值,当事务回滚时会为其赋予一个新的时间戳,先开始的事务时间戳小于后开始事务的时间戳。
每个数据项Q有两个时间戳相关的字段:
W-timestamp(Q):成功执行write(Q)的全部事务的最大时间戳
R-timestamp(Q):成功执行read(Q)的全部事务的最大时间戳
时间戳排序规则以下:
基于时间戳排序和基于锁实现的本质同样:对于可能冲突的并发操做,以串行的方式取代并发执行,于是它也是一种悲观并发控制。它们的区别主要有两点:
核心思想:事务对数据的更新首先在本身的工做空间进行,等到要写回数据库时才进行有效性检查,对不符合要求的事务进行回滚。
基于有效性检查的事务执行过程会被分为三个阶段:
有效性检查一般也是经过对事务的时间戳进行比较完成的,不过和基于时间戳排序的规则不同。
该方法容许可能冲突的操做并发执行,由于每一个事务操做的都是本身工做空间的局部变量,直到有效性检查阶段发现了冲突才回滚。于是这是一种乐观的并发策略。
快照隔离是多版本并发控制(mvcc)的一种实现方式。
其核心思想是:数据库为每一个数据项维护多个版本(快照),每一个事务只对属于本身的私有快照进行更新,在事务真正提交前进行有效性检查,使得事务正常提交更新或者失败回滚。
因为快照隔离致使事务看不到其余事务对数据项的更新,为了不出现丢失更新问题,能够采用如下两种方案避免:
事务间可能冲突的操做经过数据项的不一样版本的快照相互隔离,到真正要写入数据库时才进行冲突检测。于是这也是一种乐观并发控制。
以上只是对常见的几种并发控制技术进行了介绍,不涉及特别复杂的原理的讲解。之因此这么作一是要真的把原理和实现细节讲清楚须要涉及的东西太多,篇幅太长,从做者和读者角度而言都不是一件轻松的事,因此只对其实现的核心思想和实现要点进行了简单的介绍,其余部分就一笔带过了。二是并发控制的实现的方式太过多样,基于封锁的实现就有不少变体,mvcc多版本并发控制的实现方式就更是多样,并且不少时候会和其余并发控制方式好比封锁的方式结合起来使用。
数据库运行过程当中可能会出现故障,这些故障包括事务故障和系统故障两大类
这些故障可能会对事务和数据库状态形成破坏,于是必须提供一种技术来对各类故障进行恢复,保证数据库一致性,事务的原子性以及持久性。数据库一般以日志的方式记录数据库的操做从而在故障时进行恢复,于是能够称之为日志恢复技术。
事务的执行过程能够简化以下:
因为数据库存在当即修改和延迟修改,因此在事务执行过程当中可能存在如下状况:
<T,X,V1,V2>
:描述一次数据库写操做,T是执行写操做的事务的惟一标识,X是要写的数据项,V1是数据项的旧值,V2是数据项的新值。<T,X,V1>
:对数据库写操做的撤销操做,将事务T的X数据项恢复为旧值V1。在事务恢复阶段插入。<T start>
: 事务T开始<T commit>
: 事务T提交<T abort>
: 事务T停止关于日志,有如下两条规则
<T abort>
记录。事务正常回滚/因事务故障停止将进行redo
系统从崩溃中恢复时将先进行redo再进行undo。
如下事务将进行undo:日志中只包括<T start>
记录,但既不包括<T commit>
记录也不包括<T abort>
记录.
如下事务将进行redo:日志中包括<T start>
记录,也包括<T commit>
记录或<T abort>
记录。
假设系统从崩溃中恢复时日志记录以下
<T0 start> <T0,A,1000,950> <T0,B,2000,2050> <T0 commit> <T1 start> <T1,C,700,600>
因为T0既有start记录又有commit记录,将会对事务T0进行重作,执行相应的redo操做。
因为T1只有start记录,将会对T1进行撤销,执行相应的undo操做,撤销完毕将写入一条abort记录。
<T,X,V1,V2>
的记录,将旧值V1写入数据项X中。<T,X,V1>
,表示将数据项恢复成旧值V1,<T start>
日志记录,就中止继续扫描,并往日志中写一个<T abort>
日志记录。检查点是形如<checkpoint L>
的特殊的日志记录,L是写入检查点记录时还未提交的事务的集合,系统保证在检查点以前已经提交的事务对数据库的修改已经写入磁盘,不须要进行redo。检查点能够加快恢复的过程。
系统奔溃时的恢复过程分为两个阶段:重作阶段和撤销阶段。
重作阶段:
<T,X,V1,V2>
的更新记录或<T,X,V>
的补偿撤销记录,就重作该操做。<T start>
记录,就把T加入到undo-list中。<T abort>
或<T commit>
记录,就把T从undo-list中去除。撤销阶段:
<T start>
记录,就写入一条<T abort>
记录,4.undo-list为空,则撤销阶段结束
总结:先将日志记录中全部事务的更新按顺序重作一遍,在针对须要撤销的事务按相反的顺序执行其更新操做的撤销操做。
恢复前的日志以下,写入最后一条日志记录后系统崩溃
<T0 start> <T0,B,2000,2050> <T2 commit> <T1 start> <checkpoint {T0,T1}> //以前T2已经commit,故不用重作 <T1,C,700,600> <T1 commit> <T2 start> <T2,A,500,400> <T0,B,2000> <T0 abort> //T0回滚完成,插入该记录后系统崩溃
事务是数据库系统进行并发控制的基本单位,是数据库系统进行故障恢复的基本单位,从而也是保持数据库状态一致性的基本单位。ACID是事务的基本特性,数据库系统是经过并发控制技术和日志恢复技术来对事务的ACID进行保证的,从而能够获得以下的关于数据库事务的概念体系结构。