本文是<实现 Spring 的事务控制>系列文章中一篇。本文假设读者已经阅读并理解《实现 Spring 的事务控制,之一(必要的概念)》文中所涉及的概念(当前连接、引用计数),以及数据库连接的(new状态)
PROPAGATION_NESTED(嵌套事务)
定义:
在当前事务上开启一个子事务(Savepoint),如果递交主事务。那么连同子事务一同递交。如果递交子事务则保存点之前的所有事务都会被递交。
解释:
所谓嵌套事务,指的就是 NESTED 行为。这一点大家要格外注意。
这是由于“嵌套事务”这个词在 Spring 之后具备了多重含义。一种是指 Spring 提供的事务控制体系中那种基于多行为的嵌套事务控制策略。另外一种就是原汁原味 JDBC 提供给我们的嵌套事务。本文所提到的嵌套事务在没有特殊说明的情况下都是指后者。
好了回归正题,何为嵌套事务?
先不看定义,我们从字面理解,所谓嵌套,是指一层套着另一层的意思。那么真实情况是否是这样的呢?先看一下下面这张表:
时间 | 事务1 | 事务2 |
T1 | 开始主事务 | |
T2 | 操作1... | |
T3 | |
创建事务保存点 |
T4 | 操作2... | |
T5 | |
递交保存点 |
T6 | 操作3... | |
T7 | 回滚主事务 | |
上面这张表中列出了我们理想的事务递交方式。我们认为事务2递交不会影响到事务1。但是实际情况是错误的。
我们知道事务保存点的功能有点相当于“锚标记”它的功效是在一个长长的事务中通过保存点来分割不同的阶段。由于在标记“锚”时候是有先后顺序的,因此事务的不同阶段也是有顺序的,这个是大家都能理解的逻辑。
另外我们在学习数据库方面知识时候,知道在设置一个事务保存点之前通常会通过“begin tran....”开启事务,然后会通过“savepoint xxx”语句声明保存点。最后递交事务的时候通过“commit”语句递交。如果仅此而已则数据库事务会整体递交,递交的内容包含了自 commit 开始往前一直到最近的一个 commit 或者 begin tran 之间的所有内容。而commit 语句可以跟随一个参数“commit xxx”。那个参数就是再递交之前曾经设置的保存点名称。
在数据库中递交一个保存点的含义是指递交操作只涉及到这个保存点之前的操作。倘若我先后设置了两个保存点,然后我递交最后创建的那个保存点。那么第一个保存点之前的操作很显然也进入了数据库。因为这是保存点本身的工作性质。
我们在回到前面表格中提到的例子,当在 T5 阶段递交保存点的时候,T2 那里的操作很显然被正式保存到了数据库中。即使我们在 T7 位置执行了回滚操作。但是依然只能影响到 T6。
为此大家要各位注意,嵌套事务的真实特性。下面我们看一看 NESTED 行为的定义是怎么说的。
“在当前事务上开启一个子事务(Savepoint)”第一句就告诉我们,事务控制使用的是保存点,所以我们脑袋里应该有了一个先前印象。接下来“如果递交主事务,那么连同子事务一同递交”这也满足了我们前面提到的“commit”无参数那个情况的描述。最后“如果递交子事务则一部分主事务也会跟随递交。”这句话恰恰就是再说我们上面刚刚提到的内容。
具有 Savepoint 特征的事务
呵呵,至此为止我们已经接触到了“引用计数”、“Suspent”、“new状态”三个状态。今天再向大家介绍一种状态叫“Savepoint”至此我们已经接触到了实现复杂事务控制中所有关键的状态。
我发誓,后面还有一些状态会介绍给大家,但是请相信我。除了上面这四个状态比较复杂之外,其它的状态都很简单了。不信的话大家可以继续关注本文。
当事务管理器创建事务状态时,当前连接需要创建一个Savepoint给事务状态。这时候事务状态就具备了“Savepoint特征”。
与具有“new特征”一样,“Savepoint特征”也会协助事务管理器处理 commit & rollback 操作。
工作原理
启动事务
与前几个行为一样 NESTED 行为在启动事务的时候会判断当前连接是否存在事务。如果存在事务则安插锚点,并设置“Savepoint特征”。如果不存在事务就启动事务(我们知道此时当前连接正好满足“new特征”)。
由此可见,“new特征”和“Savepoint特征”是一个彼此排斥的情况。这在后面实现的时候会大大减少很多工作。
事务中的数据库操作
此时此刻,可以直接使用 Connection 接口畅快的使用数据库操作。由于每次进行数据库操作都要反复的申请和释放数据库连接。这会反复的使引用计数 +1,-1。 ------“这一过程中使用的数据库连接都是新的连接”。
递交/回滚事务
在启动事务阶段提到过,“Savepoint特征”和“new特征”是互斥的,因此在执行递交回滚的时候。需要先判断是否具有“Savepoint特征”,如果有就释放保存点这样就满足了嵌套事务的要求。 否则就继续判断“new”特征。
来源:oschina
链接:https://my.oschina.net/u/1166271/blog/200024