一 事务是什么
1 事务的概念
1.1 为什么须要事务
在我们日常系统开发其中,我们是不是不可避免的要对一些数据资源 进行訪问,可是我们怎么来保证我们对数据资源的訪问不会破坏数据资源的完整性呢?这个时候就须要事务了,正是引入了事务的概念。我们平时对数据资源进行操作的时候才不会破坏数据资源的完整性或者说是不变量约束 。1.2 何为事务
前面从为什么须要事务的角度,我们意识到了事务事实上就是用来保护系 统处于一致性性状态的一种措施。也能够说是一系列原子操作 的集合。
2 事务的特征
前面从事务目的的角度说明了事务究竟是什么。那么事务又是达到保证数据资源完整性的目的的呢?这须要我们来了解一下事务的特征,事务一共同拥有四个特性 (ACID) ,各自是原子性( Atomicity), 一致性( Consistency), 隔离性( Isolation), 持久性( Durability).2.1 原子性
何为原子性?之前说了事务须要保证数据资源的完整性,那么我们就须要控制对数据资源的訪问。使得对数据资源进行訪问的操作要么全部成功,否则仅仅要一个操作失败。那么全部失败(尽管有点极端 ^_^ 。可是非常必要),这样数据资源就不会由于一部分操作成功,可是一部分操作失败而引起系统不一致。2.2 一致性
何为一致性呢?一致性就是说,当我们在对数据资源的一次訪问过程中,在訪问之前和訪问之后。数据资源的状态都要处于一种完整的,满足不变量约束的状态。(比方银行转账。当从账户 A 转账到账户 B 后。账户 A 和账户B 的金额总和是不变的,这就是一种不变量约束)。事实上一致性也说出了事务的心声。这也正是事务的目的,可是要想实现此目的,事务必须满足其他的三条特征。原子性。隔离性。持久性是一致性的必要条件。
2.3 隔离性
何为隔离性?隔离性主要是考虑到了系统的并发操作,但系统对数据资 源进行訪问的时候,可能同一时候有好多个并发操作同一时候进行。这样为了保证系 统的一致性,事务必须具有一定的隔离性。使得并发运行的一些列操作互相 不要产生干扰。总之,事务的隔离性,主要是为了保证在多线程环境下。数据资源的一 致性。
2.4 持久性
何为持久性?持久性就是指在事务结束的时候,事务的结果应该被持久 的保存下来,此特征也是为一致性来服务的。试想一下,假如事务成功了, 可是此时突然断电或者其他的故障,那么此时事务的结果还是应该要保存下 来。不然系统的不变量约束就遭到了破坏。
以上是事务的四特征,以下主要来说说事务的隔离性问题,对于事务的隔离性问题, ANSI 标准规定了四个隔离级别。例如以下 :
3 事务的隔离级别
在说隔离级别曾经。我们先来明白两个问题。读取事务和写事务,读取事务仅仅是对数据库进行读操作,不会引起数据库状态变化,而写事务要对数据库进行更新。以下就以读事务和写事务来加以描写叙述:3.1 读取未提交( Read uncommited)
读取未提交隔离级别是最低的一种隔离级别,其中读事务不会堵塞任 何事务。写事务堵塞写事务。可是不堵塞读事务。正是由于写事务不堵塞读 事务。所以就造成读取事务读到的数据可能是脏的。这也就是著名的“脏读 问题”,同一时候由于读事务没有堵塞写事务,所以在读事务中的两次读取操作 可能读到不同的数据。这也就造成了著名的“不可反复读问题”,同理此种 情况下也存在“幻影读”问题。
3.2 读取已提交( Read commited)
读取已提交隔离级别中,读事务不会堵塞不论什么事务,可是写事务会堵塞 读事务和其他写事务。此时由于写事务会堵塞读事务。所以不会出现“脏读” 问题。可是由于此时读事务还是不堵塞写事务,所以“不可反复读”问题还 会出现。同一时候“幻影读”问题还是会出现。
3.3 可反复读( Repeatable Read)
可反复读隔离级别中,读事务会堵塞写事务,不堵塞读事务。写事务 会堵塞写事务和读事务,由于此时读事务堵塞了写事务。所以避免了“不可 反复读”的问题,可是此时读事务并没有堵塞对数据库的插入操作。所以此 时“幻影读”问题照样存在。3.4 序列化 (Serializable)
Serializable 隔离级别是最严格一种隔离级别,数据库系统会保证运行 此种隔离级别事务的效果和顺序运行的效果一致。只是在日常的开发过程种 非常少使用此种隔离级别,由于它严重影响了系统的性能。以上就是事务的四种隔离级别,可是实际的开发其中。我们还是须要注意以下几个问题:
1 并非全部的数据库都支持以上的四种隔离级别,详细的数据库支持的隔离级别可參考对应的数据库文档。
2 在实际的开发其中。我们常常还会遇到一个问题就是怎样在事务隔离级别和系统的并发性方面取得一个折中,假设採用 serializable 隔离级别,这样数据库就做好了并发控制,可是系统性能非常差,此时我们一般採用读取已提交的隔离级别,然后再结合以下几种并发控制的锁定策略:
* 乐观所
* 悲观锁
* 乐观离线锁
* 悲观离线锁
此时事实上并发是由应用程序来控制的,而事务的隔离由数据库系统来管理。
二 事务模型解析
首先事务模型分为好几种比方平面事务。嵌套事务等。平面事务是一个完整的不能再进行嵌套的事务,而嵌套型事务容许事务进行嵌套,事务嵌套子事务,这样主事务能够对嵌套子事务进行重试,这样添加了事务成功的整体的成功率,嵌套式事务最典型的样例就是订票。比方某人要去旅行,须要路径 A,B,C 。 D 四个不同的地方。 A 到 B 须要订火车票, B 到 C 须要订机票, C 到 D 须要订船票,那么假设採用平面事务,仅仅要 A,B,C,D 随意一段路程订票失败那么就订票失败了,这样明显成功率比較低。这样的情况下能够採用嵌套型事务来避免平面性事务的刚性失败的缺点。
上面说了常见的事务模型的类型,以下主要说一下眼下 JAVAEE 应用中,我们常见的事务,本地事务或者 resource-local 事务和全局事务或者说 JTA 事务,须要声明的是 resource-local 和 jta 事务都属于前面说的平面事务模型。在详细说这两种不同类型事务之前,首先我们来明白几个事务管理会涉及到的几个參与者:
1 资源管理器( Resource Manager) :资源管理器通常是数据库管理系统,也能够是消息队列。遗留系统等。
2 分布式事务协调者( Distributed Transaction Coordinator,DTC) 【 1 】:此功能通常是有我们所用的 JavaEE 应用server实现。比方 jboss,websphere,weblogic 等。这个角色仅仅有在 JTA 事务中才会存在。
3 事务管理器 (Transaction manager) :每个事务管理器都与对应的资源管理器所关联。它负责对分布式事务进行提交或者回滚。
4 应用程序( Application)
以上四者的关系能够用以下的图形来形象的表述:
在日常的系统开发中。我们一般都会使用数据资源(比方数据库)来对系统的状态进行保存,那么我们依据系统涉及的数据资源的多少,将事务分为 RESOURCE-LOCAL 事务或者 JTA 全局分布式事务。
1 RESOURCE-LOCAL 事务
RESOURCE-LOCAL 事务是指仅仅有一个资源管理( RM) 的事务,比方 我们系统中仅仅涉及到一个数据库,更准确点说应该是事务操作都是对同一个 数据库进行操作。
此时事务协调着和事务管理器的作用就有底层的资源管理器来实现了。比方眼下我们在採用 spring 来管理事务的时候。事实上 spring 并没有事务功能。它仅仅是封装了底层数据库的事务操作而已。
2 全局事务或者 JTA 事务
全局事务是涉及多个资源管理器,此时须要引入事务协调者来进行调节,此时就须要两阶段提交协议2PC ( two phase commit) ,以下简要说一下两阶段提交协议。
第一阶段:事务协调者发送“准备提交”消息给事务所涉及的全部的事务管理器。然后事务管理器又分送此消息给对应的资源管理器。然后事务管理器又将资源管理的响应情况告诉分布式事务协调者( DTC). 仅仅有此阶段顺利完毕后(既全部的资源管理器都允许提交事务),才会进入第二阶段。
第二阶段:当第一个阶段顺利完毕后,事务协调者告诉事务管理器去提交事务