免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 878 | 回复: 0
打印 上一主题 下一主题

Spring声明式事务管理源码解读(3) [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-01-18 14:24 |只看该作者 |倒序浏览



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


如果要理解事务提交的话,理解事务开始是一个前提条件,所以请先看第一篇文章,再来看这篇 如果你仔细看下去,我想肯定是有很多收获,因为我们确实能从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对象是有一个old的transactionInfo对象的,这个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.    }  





本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u/12821/showart_467106.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP