David.Turing's blog

 

如何理解嵌套事务(Nested Transaction)

目前,似乎很少有支持嵌套事务的中间件,但嵌套事务确实存在。
假定有Method A, Method B, Method C
A 调用 B,C
ServiceHost {    
        
    
/**   
     * 事务属性配置为 PROPAGATION_REQUIRED   
     
*/   
    
void invoke() {    
      try{
           ServiceA.invoke()
      } 
catch (Bussiness.A.Exception) { 
           abort()
      }

        
try {    
            ServiceB.invoke();    
        } 
catch (Bussiness.B.Exception) {    
            ServiceC.invoke();
        } 
catch (Bussiness.C.Exception) {    
            ServiceD.invoke();
        } catch (Bussiness.D.Exception) { 
           abort()
      }

  
        
try{
           ServiceE.invoke()
        } 
catch (Bussiness.E.Exception) { 
           ServiceF.invoke()
        }catch (Bussiness.F.Exception) { 
           abort()
      }


    }    
   

ServiceA {    
        
    
/**   
     * 事务属性配置为 PROPAGATION_NESTED, 
     × 即该事务需要被嵌套   
     
*/     
    
void methodA() {    
    }    
        
}

ServiceA, ServiceB, ServiceC, ServiceD, ServiceE, ServiceF都配置为PROPAGATION_NESTED
通过这样的嵌套规约,我们可以满足业务完整性的需求,一个ServiceParent 业务,只允许出现A-B-E , A-B-F, A-C-E, A-C-F, A-D-EA-D-F的组合,其他组合,如A-B-C, A-E, B-F都是不允许的。

 

术语上,ServiceA, B, C, D, E, F的事务均是ServiceParent事务的子事务,现在,是ServiceParent嵌套ServiceA-F,且嵌套事务的几个特性如下:

1,  假定子事务(ServiceA-F)处于活动状态(active),则parent事务(ServiceParent)不能执行任何其他操作,父事务只能commit事务,abort事务以及创建更多其它子事务。

2,  若子事务(ServiceA)被提交了,此时父事务则能够看到子事务做出的任何修改,这些修改,对其他子事务来说是隐藏的,直到父事务提交为止。

3,  同样地,如果被嵌套的事务ServiceA被回滚了,则它也不会对父事务有任何影响,且父事务servieParent也不会看到ServiceA曾经修改过的数据。

4,  最终父事务提交、回滚才会决定到子事务的提交、回滚。表达的形象点,若ServiceA“提交”后,ServiceParent却因为Service B/C/D都无法成功执行,ServiceA会回滚。这种做法依赖于JDBC 3.0 SavePoint技术。

5,  嵌套子事务提交后,它对DB的锁其实并没有释放,这些锁的控制权被转交给父事务,直到父事务提交(或回滚)后,锁才会真正释放

6,  目前,嵌套的深度不收控制,也就是,我们可对method进行以深度嵌套。

 

 

           

      现在,我们略略了解一下JDBC SavePoint技术,它给予了我们这样的能力,在一个事务里面,我们能够将已经提交的事务状态,恢复到一个事务commit以前的任意定点(这个点就是SavePoint)

            举个例子,假设我们面临这样一种情况,methodA是运算代价非常大的事务操作,methodB, methodC都是轻量级的事务,我们需要执行这样一个事务Tx={methodA->methodB->methodC}

           没有SavePoint之前,如果methodA执行成功,但是恰恰methodB失败了,那么methodA所有成果必须回滚,methodC也别想执行了,因为methodAmethodBmethodC都在同一个Tx事务中;JDBC3.0SavePoint技术为我们提供了一个无需回滚MethodA的折衷办法,可以让我们在保留methodA的成果的同时,仅仅回滚methodB,然后继续执行methodC

      回滚到SavePoint的代码类似于:

Statement stmt = conn.createStatement();
int rows = stmt.executeUpdate("INSERT INTO TAB1 (COL1) VALUES " +
"(’FIRST’)");
// set savepoint
Savepoint svpt1 = conn.setSavepoint("SAVEPOINT_1");
rows 
= stmt.executeUpdate("INSERT INTO TAB1 (COL1) " +
"VALUES (’SECOND’)");

conn.rollback(svpt1);

conn.commit();

posted on 2008-03-04 12:38 david.turing 阅读(10236) 评论(4)  编辑  收藏 所属分类: Java日积月累

评论

# re: 如何理解嵌套事务(Nested Transaction) 2008-03-17 23:32 天涯【钝】刀客

个人对事务的理解比较片面:要么一起成功,要么一起失败,所接触的用户需求基本也都是这样的,没有出现要求部分成功/部分失败的情况.
了解savePoint的概念,但是不知道hibernate里面是否支持这个操作...,有空试试.嘿嘿.  回复  更多评论   

# re: 如何理解嵌套事务(Nested Transaction) 2008-04-05 11:12 alucard

麻烦大大给个confluence破解包的解压密码
toughwhite@gmail.com 谢谢!!!!  回复  更多评论   

# re: 如何理解嵌套事务(Nested Transaction) 2008-04-30 15:04 guest

数据库本质上从来没有过嵌套事务的概念,只是应用程序为了不同的目的将对事务的操作过程嵌套起来,即使是Oracle的自治事务也可划为应用程序(存储过程或是触发器什么的),, 从应用角度讲,嵌套事务处理就是应用程序如何将应用层面的嵌套转变为数据库层面的单事务操作, 这方面Java领域的EJB,Spring提供了方面的解决方案,另外提一下JTA,它提供了事务的suspend,resume功能,实质上其实数据库事务那里有什么挂起什么的概念,其仅仅是换了一个数据库连接,这样新的数据库事务开始了,老的数据库事务便不再操作,直接其被resume.  回复  更多评论   

# re: 如何理解嵌套事务(Nested Transaction) 2008-04-30 15:12 guest

当然Save point确实提供了事务部分回退的操作,这是数据库层面提供的功能,JDBC3只是提供了支持而矣, 但是这本身还是线性的,没有什么嵌套的概念.

"要么一起成功,要么一起失败"这肯定没有问题 ,关键是事务结束只有两个可能, commit,rollback,故save point只是事务中间的一个小玩意,跟事务完整性无任何关系.  回复  更多评论   


只有注册用户登录后才能发表评论。


网站导航:
 

导航

统计

常用链接

留言簿(110)

我参与的团队

随笔分类(126)

随笔档案(155)

文章分类(9)

文章档案(19)

相册

搜索

积分与排名

最新随笔

最新评论

阅读排行榜

评论排行榜