本文是<实现 Spring 的事务控制>系列文章中一篇。本文假设读者已经阅读并理解《实现 Spring 的事务控制,之一(必要的概念)》文中所涉及的概念(当前链接、引用计数),以及数据库链接的(new状态) 数据库
若是当前存在事务则挂起当前事务,并开启一个全新的事务。新事务与已存在的事务之间彼此没有关系。 spa
REQUIRES_NEW 行为强调了独立性。它保证了每一个事务状态管理范围内锁使用的数据库链接是彼此不同的。例如独立事务会知足“A事务中存在B事务,当B事务递交的时候不影响A事务。A,B两个事务之间不存在相互关联关系。“ .net
时间 | 事务1 | 事务2 |
T1 | 开始事务 | |
T2 | 操做1... | |
T3 | |
开始事务 |
T4 | 操做2... | |
T5 | 递交事务 | |
T6 | |
回滚事务 |
定义中提到”挂起事务“这句话怎么理解? 线程
所谓“挂起”指的是将当前线程使用的数据库链接,暂时保存起来不在使用。取而代之的是一个新的数据库库链接。 对象
与挂起相对应的还有一个“恢复事务”,它们的操做是成对出现的。恢复就是将当前数据库链接释放掉,而后将之前挂起的那个数据库链接从新设为当前数据库链接。 blog
REQUIRES_NEW 行为因为出现了“挂起”这样的操做,所以它也带来了一个全新的事务状态叫“Suspent”。 接口
首先,Suspent 特征只会出如今两种重播行为中 事务
独立事务(REQUIRES_NEW) ci
非事务方式(NOT_SUPPORTED) get
如今让咱们看一看具备 Suspent 特征的事务究竟有什么特殊的。首先要想产生 Suspent 特征须要知足下面这样的条件。
当前事务状态中不具有“new”特征
在第一篇文章中介绍过,new状态是“标记当事务管理器建立新的事务状态时,当前链接的事务状态是如何的”。
咱们一瞧便知道,凡是不知足new状态条件的那么就只有一种可能了。在事务管理器建立事务对象的时候,当前链接已经开启了事务。这也难怪,由于独立事务的定义中第一句话就明白的写着:“若是当前存在事务则挂起当前事务”。
咱们再往下看“并开启一个全新的事务”这句话怎么解释?
这句话的前一句已经告诉咱们,若是存在事务就会挂起,而后在执行开启新事务。这是因为挂起事务以后,事务管理器会从新为咱们申请一个新的数据库链接。这个链接因为还还没有开启数据库事务,所以须要开启。
事务管理器在建立 REQUIRES_NEW 行为事务时,会取得当前链接这一过程会持有当前链接(引用计数+1)。注意:此时持有的数据库链接并不必定是最终在操做阶段使用的数据库链接。
而后经过判断当前链接是否存在事务状态,来决定是否经过 执行挂起事务操做。一旦执行了挂起事务的操做就至关于清空了当前的数据库链接。因此接下来须要从新申请一个数据库链接,新申请的数据库链接事务管理器也会持有它(引用计数+1)。
接下来随后会经过 doBegin 方法为这个新链接开启事务,而这个新的链接偏偏知足了“new”状态特征。所以 REQUIRES_NEW 行为事务中的事务状态是具有“new”状态的。但要注意,这个new状态指的是当前链接,也就是后申请的那个数据库链接事务状态。
不管在开启事务的时候Connection 此时此刻,能够直接使用 Connection 接口畅快的使用数据库操做。因为每次进行数据库操做都要反复的申请和释放数据库链接。这会反复的使引用计数 +1,-1。
在 REQUIRED 行为中咱们知道,凡是具备 new 状态的事务。在最后执行 commit & rollback 动做时都会真实的去执行它们。
可是在 REQUIRES_NEW 行为中,除了真实递交事务以外还会判断事务中是否存在“Suspent”特征。
在前面咱们知道在 REQUIRES_NEW 行为下有可能会同时持有两个数据库链接的引用,所以在 cleanupAfter 过程当中虽然释放了当前链接的引用计数,可是还有一个可能存在的挂起事务还没处理。
为此 REQUIRES_NEW 行为不一样于 REQUIRES 行为的是增长了一个恢复挂起事务的过程,随后又将挂起的事务引用释放掉。