Spring中事务传播特性的示例分析
这篇文章主要介绍Spring中事务传播特性的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!
一、使用方式
可以采用Transactional,配置propagation即可。打开org.springframework.transaction.annotation.Transactional
可见默认传播特性是REQUIRED
。
/** *Thetransactionpropagationtype. *<p>Defaultsto{@linkPropagation#REQUIRED}. *@seeorg.springframework.transaction.interceptor.TransactionAttribute#getPropagationBehavior() */ Propagationpropagation()defaultPropagation.REQUIRED;
二、getTransaction
顾名思义,此项属性是在事务存在交互时生效。那么到底是如何生效的呢,核心源码位于org.springframework.transaction.support.AbstractPlatformTransactionManager
。核心入口是getTransaction方法。
@Override publicfinalTransactionStatusgetTransaction(@NullableTransactionDefinitiondefinition)throwsTransactionException{ Objecttransaction=doGetTransaction(); //Cachedebugflagtoavoidrepeatedchecks. booleandebugEnabled=logger.isDebugEnabled(); // if(definition==null){ //Usedefaultsifnotransactiondefinitiongiven. definition=newDefaultTransactionDefinition(); } //已经存在事务根据事务传播特性进行处理 if(isExistingTransaction(transaction)){ //Existingtransactionfound->checkpropagationbehaviortofindouthowtobehave. returnhandleExistingTransaction(definition,transaction,debugEnabled); } //Checkdefinitionsettingsfornewtransaction. if(definition.getTimeout()<TransactionDefinition.TIMEOUT_DEFAULT){ thrownewInvalidTimeoutException("Invalidtransactiontimeout",definition.getTimeout()); } //Noexistingtransactionfound->checkpropagationbehaviortofindouthowtoproceed. //当前不存在事务MANDATORY直接抛出异常 if(definition.getPropagationBehavior()==TransactionDefinition.PROPAGATION_MANDATORY){ thrownewIllegalTransactionStateException( "Noexistingtransactionfoundfortransactionmarkedwithpropagation'mandatory'"); } //REQUIREDREQUIRES_NEWNESTED则会新建一个事务 elseif(definition.getPropagationBehavior()==TransactionDefinition.PROPAGATION_REQUIRED|| definition.getPropagationBehavior()==TransactionDefinition.PROPAGATION_REQUIRES_NEW|| definition.getPropagationBehavior()==TransactionDefinition.PROPAGATION_NESTED){ SuspendedResourcesHoldersuspendedResources=suspend(null); if(debugEnabled){ logger.debug("Creatingnewtransactionwithname["+definition.getName()+"]:"+definition); } try{ booleannewSynchronization=(getTransactionSynchronization()!=SYNCHRONIZATION_NEVER); DefaultTransactionStatusstatus=newTransactionStatus( definition,transaction,true,newSynchronization,debugEnabled,suspendedResources); doBegin(transaction,definition); prepareSynchronization(status,definition); returnstatus; } catch(RuntimeException|Errorex){ resume(null,suspendedResources); throwex; } } else{ xxx } }
可以看到,在当前不存在事务时,
MANDATORY 直接抛出异常
REQUIRED REQUIRES_NEW NESTED 自动新建一个事务。
那么存在事务时是如何处理的呢?
三、handleExistingTransaction
/** *处理已经存在事务的情况 *CreateaTransactionStatusforanexistingtransaction. */ privateTransactionStatushandleExistingTransaction( TransactionDefinitiondefinition,Objecttransaction,booleandebugEnabled) throwsTransactionException{ //NEVER已经存在事务直接抛出异常 if(definition.getPropagationBehavior()==TransactionDefinition.PROPAGATION_NEVER){ thrownewIllegalTransactionStateException( "Existingtransactionfoundfortransactionmarkedwithpropagation'never'"); } //NOT_SUPPORTED注意prepareTransactionStatus方法参数传递事务的时候传递参数为null,所以是采用非事务方式运行。执行会挂起当前事务。 if(definition.getPropagationBehavior()==TransactionDefinition.PROPAGATION_NOT_SUPPORTED){ if(debugEnabled){ logger.debug("Suspendingcurrenttransaction"); } ObjectsuspendedResources=suspend(transaction); booleannewSynchronization=(getTransactionSynchronization()==SYNCHRONIZATION_ALWAYS); returnprepareTransactionStatus( definition,null,false,newSynchronization,debugEnabled,suspendedResources); } //REQUIRES_NEW新建事务会挂起当前事务 if(definition.getPropagationBehavior()==TransactionDefinition.PROPAGATION_REQUIRES_NEW){ if(debugEnabled){ logger.debug("Suspendingcurrenttransaction,creatingnewtransactionwithname["+ definition.getName()+"]"); } SuspendedResourcesHoldersuspendedResources=suspend(transaction); try{ booleannewSynchronization=(getTransactionSynchronization()!=SYNCHRONIZATION_NEVER); DefaultTransactionStatusstatus=newTransactionStatus( definition,transaction,true,newSynchronization,debugEnabled,suspendedResources); doBegin(transaction,definition); prepareSynchronization(status,definition); returnstatus; } catch(RuntimeException|ErrorbeginEx){ resumeAfterBeginException(transaction,suspendedResources,beginEx); throwbeginEx; } } //NESTED处理嵌套事务 if(definition.getPropagationBehavior()==TransactionDefinition.PROPAGATION_NESTED){ //检查是否支持嵌套事务 if(!isNestedTransactionAllowed()){ thrownewNestedTransactionNotSupportedException( "Transactionmanagerdoesnotallownestedtransactionsbydefault-"+ "specify'nestedTransactionAllowed'propertywithvalue'true'"); } if(debugEnabled){ logger.debug("Creatingnestedtransactionwithname["+definition.getName()+"]"); } //支持的话则采用Savepoint否则开启新事务并不会挂起当前事务 if(useSavepointForNestedTransaction()){ //CreatesavepointwithinexistingSpring-managedtransaction, //throughtheSavepointManagerAPIimplementedbyTransactionStatus. //UsuallyusesJDBC3.0savepoints.NeveractivatesSpringsynchronization. DefaultTransactionStatusstatus= prepareTransactionStatus(definition,transaction,false,false,debugEnabled,null); //注意此处会创建savePoint status.createAndHoldSavepoint(); returnstatus; } else{ //Nestedtransactionthroughnestedbeginandcommit/rollbackcalls. //UsuallyonlyforJTA:Springsynchronizationmightgetactivatedhere //incaseofapre-existingJTAtransaction. booleannewSynchronization=(getTransactionSynchronization()!=SYNCHRONIZATION_NEVER); //注意此处newTransaction属性设置为true,说明确实采用了创建新事务方式来实现 DefaultTransactionStatusstatus=newTransactionStatus( definition,transaction,true,newSynchronization,debugEnabled,null); doBegin(transaction,definition); prepareSynchronization(status,definition); returnstatus; } } //AssumablyPROPAGATION_SUPPORTSorPROPAGATION_REQUIRED. if(debugEnabled){ logger.debug("Participatinginexistingtransaction"); } if(isValidateExistingTransaction()){ if(definition.getIsolationLevel()!=TransactionDefinition.ISOLATION_DEFAULT){ IntegercurrentIsolationLevel=TransactionSynchronizationManager.getCurrentTransactionIsolationLevel(); if(currentIsolationLevel==null||currentIsolationLevel!=definition.getIsolationLevel()){ ConstantsisoConstants=DefaultTransactionDefinition.constants; thrownewIllegalTransactionStateException("Participatingtransactionwithdefinition["+ definition+"]specifiesisolationlevelwhichisincompatiblewithexistingtransaction:"+ (currentIsolationLevel!=null? isoConstants.toCode(currentIsolationLevel,DefaultTransactionDefinition.PREFIX_ISOLATION): "(unknown)")); } } if(!definition.isReadOnly()){ if(TransactionSynchronizationManager.isCurrentTransactionReadOnly()){ thrownewIllegalTransactionStateException("Participatingtransactionwithdefinition["+ definition+"]isnotmarkedasread-onlybutexistingtransactionis"); } } } booleannewSynchronization=(getTransactionSynchronization()!=SYNCHRONIZATION_NEVER); //其他的传播特性则加入当前事务不会创建新事务 returnprepareTransactionStatus(definition,transaction,false,newSynchronization,debugEnabled,null); }
可以看到,当已经存在事务时,
NEVER 直接报错,不支持事务
NOT_SUPPORTED 默默按照非事务方式运行
REQUIRES_NEW 新建一个事务。
NESTED 处理嵌套事务 视情况采用savePoint或者新建事务。
其他的 加入当前事务
四、NESTED 嵌套事务
SavePoint
先简单说说SavePoint机制吧。这个也比较简单。比如一个 事务比较复杂,容易出错。那么如果当前DB支持SavePoint的话,那么创建一个SavePoint就等于创建了一个快照,可以不用每次都回滚整个事务,仅回滚到指定的SavePoint即可。
五、个人理解
NESTED这个处理确实比较复杂。个人也查了很多资料。目前个人目前理解如下:NESTED对于事务的处理主要在于级别不同。REQUIRES_NEW创建的两个事务是平级的,一个事务的成功与否对另一个事务的成功与否不产生影响。而NESTED创建的事务则名副其实,是受其父级事务影响的。一句话总结就是,子事务的成功与否不影响父级事务的成功,但是父级事务的成功与否则会影响子事务的成功。父事务回滚,子事务一定会滚。子事务回滚,父事务不一定会滚。
六、总结
最后总结如下
名称 | 说明 |
PROPAGATION_REQUIRED | 方法被调用时自动开启事务,在事务范围内使用则使用同一个事务,否则开启新事务。 默认选项。 |
PROPAGATION_SUPPORTS | 支持当前事务,如果当前没有事务,就以非事务方式执行。 |
PROPAGATION_MANDATORY | 支持当前事务,如果当前没有事务,就抛出异常。 |
PROPAGATION_REQUIRES_NEW | 新建事务,如果当前存在事务,把当前事务挂起。 |
PROPAGATION_NOT_SUPPORTED | 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 |
PROPAGATION_NEVER | 以非事务方式执行,如果当前存在事务,则抛出异常。 |
PROPAGATION_NESTED | 如果一个活动的事务存在,则运行在一个嵌套的事务中. 如果没有活动事务, 则按TransactionDefinition.PROPAGATION_REQUIRED 属性执行。需要JDBC3.0以上支持。 |
以上是“Spring中事务传播特性的示例分析”这篇文章的所有内容,感谢各位的阅读!希望分享的内容对大家有帮助,更多相关知识,欢迎关注恰卡编程网行业资讯频道!
推荐阅读
-
Spring框架基于注解开发CRUD详解
-
spring DI依赖注入方式和区别有哪些
-
spring data jpa开启批量插入、批量更新的示例分析
-
spring中怎么利用FactoryBean配置Bean
这篇文章将为大家详细讲解有关spring中怎么利用FactoryBean配置Bean,文章内容质量较高,因此小编分享给大家做个参考...
-
如何解决解决Spring Boot正常启动后访问Controller提示404的问题
小编给大家分享一下如何解决解决SpringBoot正常启动后访问Controller提示404的问题,希望大家阅读完这篇文章之后...
-
Spring中怎么解决循环依赖问题
本篇文章给大家分享的是有关Spring中怎么解决循环依赖问题,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有...
-
Spring(aop,如何通过获取代理对象实现事务切换)
Spring,aop,如何通过获取代理对象实现事务切换,恰卡网带你了解更多相关信息。Springaop获取代理对象实现...
-
Spring(bean,四种注入方式详解)
Spring,bean,四种注入方式详解,恰卡网带你了解更多相关信息。目录一、Set方式注入pojo层:1.xml文件t...
-
Spring(Cloud,如何保证微服务内安全)
-
Spring(Cloud,Config,使用本地配置文件方式)