我们分析过方法正常执行完事务提交后,本文我们继续分析目标方法抛出异常后事务的回滚流程,即 completeTransactionAfterThrowing(txInfo, ex)。
TransactionAspectSupport的completeTransactionAfterThrowing方法如下。
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; } } } }
这里首先对事务信息对象和事务状态对象做了判断,如果其中有一个为 null
则直接跳过不做处理。然后对异常类型做了判断,判断当前异常类型时触发 rollback 还是 commit动作。关于commit动作我们前面已经分析过了,本文我们分析rollback动作。
AbstractPlatformTransactionManager的rollback方法
@Override public final void rollback(TransactionStatus status) throws TransactionException { //判断事务状态是否为已完成,已完成则抛出异常 if (status.isCompleted()) { throw new IllegalTransactionStateException( "Transaction is already completed - do not call commit or rollback more than once per transaction"); } DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status; //交给了processRollback processRollback(defStatus, false); }
可以看到其rollback方法只是对status做了是否已经完成的状态校验,然后交给了processRollback方法。
AbstractPlatformTransactionManager的processRollback方法。
private void processRollback(DefaultTransactionStatus status, boolean unexpected) { try { //初值false boolean unexpectedRollback = unexpected; try { //遍历触发TransactionSynchronization的beforeCompletion方法 triggerBeforeCompletion(status); //如果有savepoint则首先回滚到savepoint位置然后释放savepoint if (status.hasSavepoint()) { if (status.isDebug()) { logger.debug("Rolling back transaction to savepoint"); } status.rollbackToHeldSavepoint(); } //如果事务是新事务,则触发rollBack动作 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"); } //修改rollbackOnly状态为true 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) { //遍历触发TransactionSynchronization 的afterCompletion 状态是STATUS_UNKNOWN triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN); throw ex; } //遍历触发TransactionSynchronization 的afterCompletion 状态是STATUS_ROLLED_BACK 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); } }
方法流程梳理如下:
遍历触发TransactionSynchronization的beforeCompletion方法
如果有savepoint则首先回滚到savepoint位置然后释放savepoint
如果事务是新事务,则触发rollBack动作
如果当前事务是一个已经存在的事务,则可能设置事务状态rollbackOnly为true
遍历触发TransactionSynchronization 的afterCompletion
完成后清理事务信息-cleanupAfterCompletion
可以看到,这里同前文提交分析流程类型,同样触发了TransactionSynchronization的钩子函数,对事务进行了判断处理最后清理事务资源。
cleanupAfterCompletion同前文一致,TransactionSynchronization我们另起篇章分析。我们接下来看下核心方法doRollback(status);。
DataSourceTransactionManager的doRollback方法
@Override protected void doRollback(DefaultTransactionStatus status) { DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction(); Connection con = txObject.getConnectionHolder().getConnection(); if (status.isDebug()) { logger.debug("Rolling back JDBC transaction on Connection [" + con + "]"); } try { con.rollback(); } catch (SQLException ex) { throw new TransactionSystemException("Could not roll back JDBC transaction", ex); } }
方法如上所示其从事务对象里面获取到连接对象,然后触发数据库连接对象的rollback方法。
本文这里获取到的数据库连接对象是:HikariProxyConnection@2062395789 wrapping com.mysql.cj.jdbc.ConnectionImpl@12ee6186。可以看到其内有委派对象delegate=ConnectionImpl
ProxyConnection 的rollback方法
@Override public void rollback() throws SQLException { delegate.rollback(); isCommitStateDirty = false; lastAccess = currentTime(); }
再往下就交给了MySQL驱动来实现这个功能,如下所示,其最终触发了this.session.execSQL(null, "rollback", -1, null, false, this.nullStatementResultSetFactory, null, false);