spring的UnexpectedRollbackException事務(wù)嵌套示例解析
UnexpectedRollbackException
/** * Thrown when an attempt to commit a transaction resulted * in an unexpected rollback. * * @author Rod Johnson * @since 17.03.2003 */ @SuppressWarnings("serial") public class UnexpectedRollbackException extends TransactionException { /** * Constructor for UnexpectedRollbackException. * @param msg the detail message */ public UnexpectedRollbackException(String msg) { super(msg); } /** * Constructor for UnexpectedRollbackException. * @param msg the detail message * @param cause the root cause from the transaction API in use */ public UnexpectedRollbackException(String msg, Throwable cause) { super(msg, cause); } }
UnexpectedRollbackException繼承了TransactionException,一般是事務(wù)嵌套,內(nèi)層事務(wù)拋出了異常,外層事務(wù)給catch住了,然后試圖提交事務(wù)報(bào)錯(cuò)
示例
@Transactional public Customer createWithCatch(String name, String email) { Customer customer = customerRepository.save(new Customer(name, email)); try { demoService.throwExInTx(0); } catch (Exception e) { log.error(e.getMessage(), e); } return customer; } // demoService @Transactional public void throwExInTx(int i) { int result = 1 / i; }
這里內(nèi)層事務(wù)throwExInTx拋出了異常,而外層事務(wù)createWithCatch給catch住了,最后提交事務(wù)則報(bào)UnexpectedRollbackException異常
源碼解析
invokeWithinTransaction
org/springframework/transaction/interceptor/TransactionAspectSupport.java
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass, final InvocationCallback invocation) throws Throwable { //...... if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) { // Standard transaction demarcation with getTransaction and commit/rollback calls. TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification); Object retVal; try { // This is an around advice: Invoke the next interceptor in the chain. // This will normally result in a target object being invoked. retVal = invocation.proceedWithInvocation(); } catch (Throwable ex) { // target invocation exception completeTransactionAfterThrowing(txInfo, ex); throw ex; } finally { cleanupTransactionInfo(txInfo); } if (vavrPresent && VavrDelegate.isVavrTry(retVal)) { // Set rollback-only in case of Vavr failure matching our rollback rules... TransactionStatus status = txInfo.getTransactionStatus(); if (status != null && txAttr != null) { retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status); } } commitTransactionAfterReturning(txInfo); return retVal; } //...... }
TransactionAspectSupport的invokeWithinTransaction方法在執(zhí)行invocation.proceedWithInvocation()時(shí)會(huì)catch住異常,然后執(zhí)行completeTransactionAfterThrowing
completeTransactionAfterThrowing
org/springframework/transaction/interceptor/TransactionAspectSupport.java
/** * Handle a throwable, completing the transaction. * We may commit or roll back, depending on the configuration. * @param txInfo information about the current transaction * @param ex throwable encountered */ protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex) { if (txInfo != null && txInfo.getTransactionStatus() != null) { if (logger.isTraceEnabled()) { logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() + "] after exception: " + ex); } if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) { try { txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus()); } catch (TransactionSystemException ex2) { logger.error("Application exception overridden by rollback exception", ex); ex2.initApplicationException(ex); throw ex2; } catch (RuntimeException | Error ex2) { logger.error("Application exception overridden by rollback exception", ex); throw ex2; } } else { // We don't roll back on this exception. // Will still roll back if TransactionStatus.isRollbackOnly() is true. try { txInfo.getTransactionManager().commit(txInfo.getTransactionStatus()); } catch (TransactionSystemException ex2) { logger.error("Application exception overridden by commit exception", ex); ex2.initApplicationException(ex); throw ex2; } catch (RuntimeException | Error ex2) { logger.error("Application exception overridden by commit exception", ex); throw ex2; } } } }
completeTransactionAfterThrowing會(huì)判斷該異常是否要rollback,需要rollback的話,則執(zhí)行txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus())
processRollback
org/springframework/transaction/support/AbstractPlatformTransactionManager.java
/** * Process an actual rollback. * The completed flag has already been checked. * @param status object representing the transaction * @throws TransactionException in case of rollback failure */ private void processRollback(DefaultTransactionStatus status, boolean unexpected) { try { boolean unexpectedRollback = unexpected; try { triggerBeforeCompletion(status); if (status.hasSavepoint()) { if (status.isDebug()) { logger.debug("Rolling back transaction to savepoint"); } status.rollbackToHeldSavepoint(); } else if (status.isNewTransaction()) { if (status.isDebug()) { logger.debug("Initiating transaction rollback"); } doRollback(status); } else { // Participating in larger transaction if (status.hasTransaction()) { if (status.isLocalRollbackOnly() || isGlobalRollbackOnParticipationFailure()) { if (status.isDebug()) { logger.debug("Participating transaction failed - marking existing transaction as rollback-only"); } doSetRollbackOnly(status); } else { if (status.isDebug()) { logger.debug("Participating transaction failed - letting transaction originator decide on rollback"); } } } else { logger.debug("Should roll back transaction but cannot - no transaction available"); } // Unexpected rollback only matters here if we're asked to fail early if (!isFailEarlyOnGlobalRollbackOnly()) { unexpectedRollback = false; } } } catch (RuntimeException | Error ex) { triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN); throw ex; } triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK); // Raise UnexpectedRollbackException if we had a global rollback-only marker if (unexpectedRollback) { throw new UnexpectedRollbackException( "Transaction rolled back because it has been marked as rollback-only"); } } finally { cleanupAfterCompletion(status); } }
processRollback這里會(huì)判斷,如果該事務(wù)外層還有事務(wù),則判斷status.isLocalRollbackOnly()或者是isGlobalRollbackOnParticipationFailure(默認(rèn)返回true),然后執(zhí)行doSetRollbackOnly(status)
doSetRollbackOnly
org/springframework/orm/jpa/JpaTransactionManager.java
protected void doSetRollbackOnly(DefaultTransactionStatus status) { JpaTransactionObject txObject = (JpaTransactionObject) status.getTransaction(); if (status.isDebug()) { logger.debug("Setting JPA transaction on EntityManager [" + txObject.getEntityManagerHolder().getEntityManager() + "] rollback-only"); } txObject.setRollbackOnly(); }
doSetRollbackOnly會(huì)獲取txObject執(zhí)行setRollbackOnly
setRollbackOnly
org/springframework/orm/jpa/JpaTransactionManager.java
public void setRollbackOnly() { EntityTransaction tx = getEntityManagerHolder().getEntityManager().getTransaction(); if (tx.isActive()) { tx.setRollbackOnly(); } if (hasConnectionHolder()) { getConnectionHolder().setRollbackOnly(); } }
setRollbackOnly這里會(huì)執(zhí)行tx.setRollbackOnly()、getConnectionHolder().setRollbackOnly()標(biāo)記為rollbackOnly
外層事務(wù)processCommit
org/springframework/transaction/support/AbstractPlatformTransactionManager.java
/** * Process an actual commit. * Rollback-only flags have already been checked and applied. * @param status object representing the transaction * @throws TransactionException in case of commit failure */ private void processCommit(DefaultTransactionStatus status) throws TransactionException { try { boolean beforeCompletionInvoked = false; try { boolean unexpectedRollback = false; prepareForCommit(status); triggerBeforeCommit(status); triggerBeforeCompletion(status); beforeCompletionInvoked = true; if (status.hasSavepoint()) { if (status.isDebug()) { logger.debug("Releasing transaction savepoint"); } unexpectedRollback = status.isGlobalRollbackOnly(); status.releaseHeldSavepoint(); } else if (status.isNewTransaction()) { if (status.isDebug()) { logger.debug("Initiating transaction commit"); } unexpectedRollback = status.isGlobalRollbackOnly(); doCommit(status); } else if (isFailEarlyOnGlobalRollbackOnly()) { unexpectedRollback = status.isGlobalRollbackOnly(); } // Throw UnexpectedRollbackException if we have a global rollback-only // marker but still didn't get a corresponding exception from commit. if (unexpectedRollback) { throw new UnexpectedRollbackException( "Transaction silently rolled back because it has been marked as rollback-only"); } } catch (UnexpectedRollbackException ex) { // can only be caused by doCommit triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK); throw ex; } catch (TransactionException ex) { // can only be caused by doCommit if (isRollbackOnCommitFailure()) { doRollbackOnCommitException(status, ex); } else { triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN); } throw ex; } catch (RuntimeException | Error ex) { if (!beforeCompletionInvoked) { triggerBeforeCompletion(status); } doRollbackOnCommitException(status, ex); throw ex; } // Trigger afterCommit callbacks, with an exception thrown there // propagated to callers but the transaction still considered as committed. try { triggerAfterCommit(status); } finally { triggerAfterCompletion(status, TransactionSynchronization.STATUS_COMMITTED); } } finally { cleanupAfterCompletion(status); } }
processCommit在unexpectedRollback為true的時(shí)候會(huì)拋出UnexpectedRollbackException(Transaction silently rolled back because it has been marked as rollback-only);這里是status.isGlobalRollbackOnly()被標(biāo)記為true了,因而unexpectedRollback為true
小結(jié)
UnexpectedRollbackException繼承了TransactionException,一般是事務(wù)嵌套,內(nèi)層事務(wù)拋出了異常,外層事務(wù)給catch住了,然后試圖提交事務(wù)報(bào)錯(cuò)UnexpectedRollbackException(Transaction silently rolled back because it has been marked as rollback-only)。
以上就是spring的UnexpectedRollbackException事務(wù)嵌套示例解析的詳細(xì)內(nèi)容,更多關(guān)于spring 事務(wù)嵌套的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
java方法重寫(xiě)時(shí)需要注意的問(wèn)題
大家好,本篇文章主要講的是java方法重寫(xiě)時(shí)需要注意的問(wèn)題,感興趣的同學(xué)趕快來(lái)看一看吧,對(duì)你有幫助的話記得收藏一下,方便下次瀏覽2021-12-12Spring cloud Eureka注冊(cè)中心搭建的方法
這篇文章主要介紹了Spring cloud Eureka注冊(cè)中心搭建的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-04-04SpringBoot 使用 FTP 操作文件的過(guò)程(刪除、上傳、下載文件)
這篇文章主要介紹了SpringBoot 使用 FTP 操作文件,主要包括配置ftp服務(wù)器,上傳、刪除、下載文件操作,本文結(jié)合示例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2022-12-12java實(shí)現(xiàn)上傳圖片進(jìn)行切割的方法
這篇文章主要介紹了java實(shí)現(xiàn)上傳圖片進(jìn)行切割的方法,以完整實(shí)例形式分析了Java針對(duì)上傳圖片進(jìn)行切割的技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2015-02-02springboot2中使用@JsonFormat注解不生效的解決
這篇文章主要介紹了springboot2中使用@JsonFormat注解不生效的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-02-02springboot的LogbackLoggingSystem配置加載流程解析
這篇文章主要介紹了springboot的LogbackLoggingSystem配置加載流程源碼分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-11-11Zuul 實(shí)現(xiàn)網(wǎng)關(guān)轉(zhuǎn)發(fā)的五種方式小結(jié)
這篇文章主要介紹了Zuul 實(shí)現(xiàn)網(wǎng)關(guān)轉(zhuǎn)發(fā)的五種方式小結(jié),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07