Spring声明式事务管理源码解读之事务提交Word文档格式.docx
《Spring声明式事务管理源码解读之事务提交Word文档格式.docx》由会员分享,可在线阅读,更多相关《Spring声明式事务管理源码解读之事务提交Word文档格式.docx(17页珍藏版)》请在冰豆网上搜索。
.
//TheTransactionAttributeSourceshouldbepassedthetargetclass
//aswellasthemethod,whichmaybefromaninterface
ClasstargetClass=(invocation.getThis()!
=null)?
invocation.getThis().getClass():
null;
//Createtransactionifnecessary.
TransactionInfotxInfo=createTransactionIfNecessary(invocation.getMethod(),targetClass);
ObjectretVal=null;
try{
//Thisisanaroundadvice.
//Invokethenextinterceptorinthechain.
//Thiswillnormallyresultinatargetobjectbeinginvoked.
retVal=invocation.proceed();
}
catch(Throwableex){
//targetinvocationexception
doCloseTransactionAfterThrowing(txInfo,ex);
throwex;
finally{
doFinally(txInfo);
//业务方法出栈后必须先执行的一个方法
doCommitTransactionAfterReturning(txInfo);
returnretVal;
publicObjectinvoke(MethodInvocationinvocation)throwsThrowable{
//Workoutthetargetclass:
.
//TheTransactionAttributeSourceshouldbepassedthetargetclass
//aswellasthemethod,whichmaybefromaninterface
ClasstargetClass=(invocation.getThis()!
//Createtransactionifnecessary.
TransactionInfotxInfo=createTransactionIfNecessary(invocation.getMethod(),targetClass);
ObjectretVal=null;
try{
//Thisisanaroundadvice.
//Invokethenextinterceptorinthechain.
//Thiswillnormallyresultinatargetobjectbeinginvoked.
retVal=invocation.proceed();
}
catch(Throwableex){
//targetinvocationexception
doCloseTransactionAfterThrowing(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;
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方法吧:
txInfo.newTransactionStatus(this.transactionManager.getTransaction(txAttr));
txInfo.newTransactionStatus(this.transactionManager.getTransaction(txAttr));
再看看transactionManager.getTransaction(txAttr)方法吧:
publicfinalTransactionStatusgetTransaction(TransactionDefinitiondefinition)throwsTransactionException{
elseif(definition.getPropagationBehavior()==TransactionDefinition.PROPAGATION_REQUIRED||
definition.getPropagationBehavior()==TransactionDefinition.PROPAGATION_REQUIRES_NEW||
definition.getPropagationBehavior()==TransactionDefinition.PROPAGATION_NESTED){
if(debugEnabled){
logger.debug("
Creatingnewtransactionwithname["
+definition.getName()+"
]"
);
doBegin(transaction,definition);
booleannewSynchronization=(this.transactionSynchronization!
=SYNCHRONIZATION_NEVER);
returnnewTransactionStatus(definition,transaction,true,newSynchronization,debugEnabled,null);
//注意这里的返回值,返回的就是一个TransactionStatus对象,这个对象表明了一个事务的状态,比如说是否是一个新的事务,事务是否已经结束,等等,这个对象是非常重要的,在事务提交的时候还是会用到它的。
publicfinalTransactionStatusgetTransaction(TransactionDefinitiondefinition)throwsTransactionException{
elseif(definition.getPropagationBehavior()==TransactionDefinition.PROPAGATION_REQUIRED||
definition.getPropagationBehavior()==TransactionDefinition.PROPAGATION_REQUIRES_NEW||
definition.getPropagationBehavior()==TransactionDefinition.PROPAGATION_NESTED){
if(debugEnabled){
logger.debug("
doBegin(transaction,definition);
booleannewSynchronization=(this.transactionSynchronization!
returnnewTransactionStatus(definition,transaction,true,newSynchronization,debugEnabled,null);
}
还有一点需要说明的是,AService的方法在执行之前创建的transactionstatus确实是通过这个方法创建的,但是,BService的方法在执行之前创建transactionstatus的方法就与这个不一样了,下面会有详解。
回顾了事务开始时所调用的方法之后,是不是觉得现在对spring如何处理事务越来越清晰了呢。
由于这么几个方法的调用,每个方法入栈之前它的事务状态就已经被设置好了。
这个事务状态就是为了在方法出栈时被调用而准备的。
让我们再次回到BService中的方法出栈的那个时间段,看看spring都做了些什么,我们知道,后入栈的肯定是先出栈,BService中的方法后入栈,拿它肯定要先出栈了,它出栈的时候是要判断是否要提交事务,释放资源的,让我们来看看TransactionInterceptor的invoke的最后那个方法doCommitTransactionAfterReturning:
protectedvoiddoCommitTransactionAfterReturning(TransactionInfotxInfo){
if(txInfo!
=null&
amp;
&
txInfo.hasTransaction()){
if(logger.isDebugEnabled()){
Invokingcommitfortransactionon"
+txInfo.joinpointIdentification());
this.transactionMmit(txInfo.getTransactionStatus());
//瞧:
提交事务时用到了表明事务状态的那个TransactionStatus对象了。
protectedvoiddoCommitTransactionAfterReturning(TransactionInfotxInfo){
if(txInfo!
txInfo.hasTransaction()){
if(logger.isDebugEnabled()){
this.transactionMmit(txInfo.getTransactionStatus());
看这个方法的名字就知道spring是要在业务方法出栈时提交事务,貌似很简单,但是事实是这样的吗?
我们接着往下看。
publicfinalvoidcommit(TransactionStatusstatus)throwsTransactionException{
DefaultTransactionStatusdefStatus=(DefaultTransactionStatus)status;
if(defStatus.isCompleted()){
thrownewIllegalTransactionStateException(
"
Transactionisalreadycompleted-donotcallcommitorrollbackmorethanoncepertransaction"
if(defStatus.isLocalRollbackOnly()){
if(defStatus.isDebug()){
Transactionalcodehasrequestedrollback"
processRollback(defStatus);
return;
if(!
shouldCommitOnGlobalRollbackOnly()&
defStatus.isGlobalRollbackOnly()){
Globaltransactionismarkedasrollback-onlybuttransactionalcoderequestedcommit"
thrownewUnexpectedRollbackException(
Transactionhasbeenrolledbackbecauseithasbeenmarkedasrollback-only"
processCommit(defStatus);
publicfinalvoidcommit(TransactionStatusstatus)throwsTransactionException{
DefaultTransactionStatusdefStatus=(DefaultTransactionStatus)status;
if(defStatus.isCompleted()){
thrownewIllegalTransactionStateException(
"
if(defStatus.isLocalRollbackOnly()){
if(defStatus.isDebug()){
processRo