Chinaunix首页 | 论坛 | 博客
  • 博客访问: 405820
  • 博文数量: 38
  • 博客积分: 1490
  • 博客等级: 上尉
  • 技术积分: 406
  • 用 户 组: 普通用户
  • 注册时间: 2006-01-08 00:52
文章分类

全部博文(38)

文章存档

2014年(1)

2013年(1)

2008年(6)

2007年(7)

2006年(23)

我的朋友

分类: Java

2008-01-18 14:24:05

<----- 接2续 ----->

 

上次说到spring声明式事务管理的事务开始部分,按流程来讲,下面应该提交事务了, spring的声明式事务管理其实是比较复杂的,事实上这种复杂性正是由于事务本身的复杂性导致的,如果能用两三句话就把这部分内容说清楚是不现实的,也是不成熟的,而我对这部分的理解也可能是不全面的,还是那句话,希望大家和我一起把本贴的质量提交起来。在下面的文章中,我讲会多次提到第一篇文章,第一篇文章的地址是:

 

如果要理解事务提交的话,理解事务开始是一个前提条件,所以请先看第一篇文章,再来看这篇 如果你仔细看下去,我想肯定是有很多收获,因为我们确实能从spring的代码和思想中学到很多东西。

 

正文:

其实俺的感觉就是事务提交要比事务开始复杂,看事务是否提交我们还是要回到TransactionInterceptor类的invoke方法。

 

代码

1.       public Object invoke(MethodInvocation invocation) throws Throwable {   

2.               // Work out the target class: may be null.   

3.               // The TransactionAttributeSource should be passed the target class   

4.               // as well as the method, which may be from an interface   

5.               Class targetClass = (invocation.getThis() != null) ? invocation.getThis().getClass() : null;   

6.                  

7.               // Create transaction if necessary.   

8.               TransactionInfo txInfo = createTransactionIfNecessary(invocation.getMethod(), targetClass);   

9.         

10.            Object retVal = null;   

11.            try {   

12.                // This is an around advice.   

13.                // Invoke the next interceptor in the chain.   

14.                // This will normally result in a target object being invoked.   

15.                retVal = invocation.proceed();   

16.            }   

17.            catch (Throwable ex) {   

18.                // target invocation exception   

19.                doCloseTransactionAfterThrowing(txInfo, ex);   

20.                throw ex;   

21.            }   

22.            finally {   

23.                doFinally(txInfo);//业务方法出栈后必须先执行的一个方法   

24.            }   

25.            doCommitTransactionAfterReturning(txInfo);   

26.            return retVal;   

27.    }  

 

其中的doFinally(txInfo)那一行很重要,也就是说不管如何,这个doFinally方法都是要被调用的,为什么它这么重要呢,举个例子: 我们还是以propregation_required来举例子吧,假设情况是这样的,AService中有一个方法调用了BService中的,这两个方法都处在事务体之中,他们的传播途径都是required。那么调用开始了,AService的方法首先入方法栈,并创建了TransactionInfo的实例,接着BService的方法入栈,又创建了一个TransactionInfo的实例,而重点要说明的是TransactionInfo是一个自身关联的内部类,第二个方法入栈时,会给新创建的TransactionInfo的实例设置一个属性,就是TransactionInfo对象中的private TransactionInfo oldTransactionInfo;属性,这个属性表明BService方法的创建的TransactionInfo对象是有一个oldtransactionInfo对象的,这个oldTransactionInfo对象就是AService方法入栈时创建的TransactionInfo对象,我们还记得在createTransactionIfNecessary方法里有这样一个方法吧:

 

代码

1.       protected TransactionInfo createTransactionIfNecessary(Method method, Class targetClass) {   

2.                // We always bind the TransactionInfo to the thread, even if we didn't create   

3.               // a new transaction here. This guarantees that the TransactionInfo stack   

4.               // will be managed correctly even if no transaction was created by this aspect.   

5.               txInfo.bindToThread();   

6.               return txInfo;   

7.           }   

  

就是这个bindToThread()方法在作怪:   

 

1.       private void bindToThread() {   

2.                   // Expose current TransactionStatus, preserving any existing transactionStatus for   

3.                   // restoration after this transaction is complete.   

4.                   oldTransactionInfo = (TransactionInfo) currentTransactionInfo.get();   

5.                   currentTransactionInfo.set(this);   

6.            }  

 

如果当前线程中已经有了一个TransactionInfo,则拿出来放到新建的transactionInfo对象的oldTransactionInfo属性中,然后再把新建的TransactionInfo设置到当前线程中。

这里有一个概念要搞清楚,就是TransactionInfo对象并不是表明事务状态的对象,表明事务状态的对象是TransactionStatus对象,这个对象同样是TransactionInfo的一个属性(这一点,我在前面一篇文章中并没有讲清楚)。

接下来BService中的那个方法返回,那么该它退栈了,它退栈后要做的就是doFinally方法,即把它的oldTransactionInfo设置到当前线程中(这个TransactionInfo对象显然就是AService方法入栈时创建的,怎么现在又要设置到线程中去呢,原因就是BService的方法出栈时并不提交事务,因为BService的传播途径是required,所以要把栈顶的方法所创建transactioninfo给设置到当前线程中),即调用AService的方法时所创建的TransactionInfo对象。那么在AServie的方法出栈时同样会设置TransactionInfo对象的oldTransactionInfo到当前线程,这时候显然oldTransactionInfo是空的,但AService中的方法会提交事务,所以它的oldTransactionInfo也应该是空了。

在这个小插曲之后,么接下来就应该是到提交事务了,之前在AService的方法出栈时,我们拿到了它入栈时创建的TransactionInfo对象,这个对象中包含了AService的方法事务状态。即TransactionStatus对象,很显然,太显然了,事务提交中的任何属性都和事务开始时的创建的对象息息相关,这个TransactionStatus对象哪里来的,我们再回头看看createTransactionIfNessary方法吧:

 

代码

1.       protected TransactionInfo createTransactionIfNecessary(Method method, Class targetClass) {   

2.                   txInfo.newTransactionStatus(this.transactionManager.getTransaction(txAttr));   

3.               }  

 

再看看transactionManager.getTransaction(txAttr)方法吧:

 

代码

1.       public final TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {   

2.                ………………………..

3.               else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||   

4.                       definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||   

5.                   definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {   

6.                   if (debugEnabled) {   

7.                       logger.debug("Creating new transaction with name [" + definition.getName() + "]");   

8.                   }   

9.                   doBegin(transaction, definition);   

10.                boolean newSynchronization = (this.transactionSynchronization != SYNCHRONIZATION_NEVER);   

11.                return newTransactionStatus(definition, transaction, true, newSynchronization, debugEnabled, null);//注意这里的返回值,返回的就是一个TransactionStatus对象,这个对象表明了一个事务的状态,比如说是否是一个新的事务,事务是否已经结束,等等,这个对象是非常重要的,在事务提交的时候还是会用到它的。           

12.                }   

13.    }  

 

<------ 未完 ------>

 

阅读(3566) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~