您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 市场营销 > Spring声明式事务管理源码解读之事务提交
Spring声明式事务管理源码解读之事务提交简介:上次说到spring声明式事务管理的事务开始部分,按流程来讲,下面应该提交事务了,spring的声明式事务管理其实是比较复杂的,事实上这种复杂性正是由于事务本身的复杂性导致的,如果能用两三句话就把这部分内容说清楚是不现实的,也是不成熟的,而我对这部分的理解也可能是不全面的,还是那句话,希望大家和我一起把本贴的质量提交起来。在下面的文章中,我讲会多次提到第一篇文章,第一篇文章的地址是:如果要理解事务提交的话,理解事务开始是一个前提条件,所以请先看第一篇文章,再来看这篇如果你仔细看下去,我想肯定是有很多收获,因为我们确实能从spring的代码和思想中学到很多东西。正文:其实俺的感觉就是事务提交要比事务开始复杂,看事务是否提交我们还是要回到TransactionInterceptor类的invoke方法Java代码publicObjectinvoke(MethodInvocationinvocation)throwsThrowable{//Workoutthetargetclass:maybe<code>null</code>.//TheTransactionAttributeSourceshouldbepassedthetargetclass//aswellasthemethod,whichmaybefromaninterfaceClasstargetClass=(invocation.getThis()!=null)?invocation.getThis().getClass():null;//Createtransactionifnecessary.TransactionInfotxInfo=createTransactionIfNecessary(invocation.getMethod(),targetClass);ObjectretVal=null;try{//Thisisanaroundadvice.//Invokethenextinterceptorinthechain.//Thiswillnormallyresultinatargetobjectbeinginvoked.retVal=invocation.proceed();}catch(Throwableex){//targetinvocationexceptiondoCloseTransactionAfterThrowing(txInfo,ex);throwex;}finally{doFinally(txInfo);//业务方法出栈后必须先执行的一个方法}doCommitTransactionAfterReturning(txInfo);returnretVal;}publicObjectinvoke(MethodInvocationinvocation)throwsThrowable{//Workoutthetargetclass:maybe<code>null</code>.//TheTransactionAttributeSourceshouldbepassedthetargetclass//aswellasthemethod,whichmaybefromaninterfaceClasstargetClass=(invocation.getThis()!=null)?invocation.getThis().getClass():null;//Createtransactionifnecessary.TransactionInfotxInfo=createTransactionIfNecessary(invocation.getMethod(),targetClass);ObjectretVal=null;try{//Thisisanaroundadvice.//Invokethenextinterceptorinthechain.//Thiswillnormallyresultinatargetobjectbeinginvoked.retVal=invocation.proceed();}catch(Throwableex){//targetinvocationexceptiondoCloseTransactionAfterThrowing(txInfo,ex);throwex;}finally{doFinally(txInfo);//业务方法出栈后必须先执行的一个方法}doCommitTransactionAfterReturning(txInfo);returnretVal;}其中的doFinally(txInfo)那一行很重要,也就是说不管如何,这个doFinally方法都是要被调用的,为什么它这么重要呢,举个例子:我们还是以propregation_required来举例子吧,假设情况是这样的,AService中有一个方法调用了BService中的,这两个方法都处在事务体之中,他们的传播途径都是required。那么调用开始了,AService的方法首先入方法栈,并创建了TransactionInfo的实例,接着BService的方法入栈,又创建了一个TransactionInfo的实例,而重点要说明的是TransactionInfo是一个自身关联的内部类,第二个方法入栈时,会给新创建的TransactionInfo的实例设置一个属性,就是TransactionInfo对象中的privateTransactionInfooldTransactionInfo;属性,这个属性表明BService方法的创建的TransactionInfo对象是有一个old的transactionInfo对象的,这个oldTransactionInfo对象就是AService方法入栈时创建的TransactionInfo对象,我们还记得在createTransactionIfNecessary方法里有这样一个方法吧:Java代码protectedTransactionInfocreateTransactionIfNecessary(Methodmethod,ClasstargetClass){//WealwaysbindtheTransactionInfotothethread,evenifwedidn'tcreate//anewtransactionhere.ThisguaranteesthattheTransactionInfostack//willbemanagedcorrectlyevenifnotransactionwascreatedbythisaspect.txInfo.bindToThread();returntxInfo;}就是这个bindToThread()方法在作怪:privatevoidbindToThread(){//ExposecurrentTransactionStatus,preservinganyexistingtransactionStatusfor//restorationafterthistransactioniscomplete.oldTransactionInfo=(TransactionInfo)currentTransactionInfo.get();currentTransactionInfo.set(this);}protectedTransactionInfocreateTransactionIfNecessary(Methodmethod,ClasstargetClass){//WealwaysbindtheTransactionInfotothethread,evenifwedidn'tcreate//anewtransactionhere.ThisguaranteesthattheTransactionInfostack//willbemanagedcorrectlyevenifnotransactionwascreatedbythisaspect.txInfo.bindToThread();returntxInfo;}就是这个bindToThread()方法在作怪:privatevoidbindToThread(){//ExposecurrentTransactionStatus,preservinganyexistingtransactionStatusfor//restorationafterthistransactioniscomplete.oldTransactionInfo=(TransactionInfo)currentTransactionInfo.get();currentTransactionInfo.set(this);}如果当前线程中已经有了一个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方法吧:Java代码protectedTransactionInfocreateTransactionIfNecessary(Methodmethod,ClasstargetClass){txInfo.newTransactionStatus(this.transactionManager.getTransaction(txAttr));}protectedTransactionInfocreateTransactionIfNecessary(Methodmethod,ClasstargetClass){txInfo.newTransactionStatus(this.transactionManager.getTransaction(txAttr));}再看看transactionManager.getTransaction(txAttr)方法吧:Java代码publicfinalTransactionStatusgetTransac
本文标题:Spring声明式事务管理源码解读之事务提交
链接地址:https://www.777doc.com/doc-3293944 .html