spring的UnexpectedRollbackException事务嵌套示例解析
作者:codecraft
这篇文章主要为大家介绍了spring的UnexpectedRollbackException事务嵌套示例解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
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,一般是事务嵌套,内层事务抛出了异常,外层事务给catch住了,然后试图提交事务报错
示例
@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; }
这里内层事务throwExInTx抛出了异常,而外层事务createWithCatch给catch住了,最后提交事务则报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方法在执行invocation.proceedWithInvocation()时会catch住异常,然后执行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会判断该异常是否要rollback,需要rollback的话,则执行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这里会判断,如果该事务外层还有事务,则判断status.isLocalRollbackOnly()或者是isGlobalRollbackOnParticipationFailure(默认返回true),然后执行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会获取txObject执行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这里会执行tx.setRollbackOnly()、getConnectionHolder().setRollbackOnly()标记为rollbackOnly
外层事务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的时候会抛出UnexpectedRollbackException(Transaction silently rolled back because it has been marked as rollback-only);这里是status.isGlobalRollbackOnly()被标记为true了,因而unexpectedRollback为true
小结
UnexpectedRollbackException继承了TransactionException,一般是事务嵌套,内层事务抛出了异常,外层事务给catch住了,然后试图提交事务报错UnexpectedRollbackException(Transaction silently rolled back because it has been marked as rollback-only)。
以上就是spring的UnexpectedRollbackException事务嵌套示例解析的详细内容,更多关于spring 事务嵌套的资料请关注脚本之家其它相关文章!