Spring源码学习21

本文分析下:事务回滚和事务提交

1.事务回滚方法completeTransactionAfterThrowing(txInfo, ex)

/**
	 * 处理一个throwable,完成事务。
	 * 我们可能会提交或回滚,具体取决于配置。
	 * @param txInfo information about the current transaction
	 * @param ex throwable encountered
	 */
	protected void completeTransactionAfterThrowing(TransactionInfo txInfo, Throwable ex) {
		//判断是否存在事务
		if (txInfo != null && txInfo.hasTransaction()) {
			if (logger.isTraceEnabled()) {
				logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() +
						"] after exception: " + ex);
			}
			//判断异常是否需要回滚
			if (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 ex2) {
					logger.error("Application exception overridden by rollback exception", ex);
					throw ex2;
				}
				catch (Error err) {
					logger.error("Application exception overridden by rollback error", ex);
					throw err;
				}
			}
			else {
				// We don't roll back on this exception.
				// Will still roll back if TransactionStatus.isRollbackOnly() is true.
				// 我们不需要对该异常回滚
				// 如果TransactionStatus.isRollbackOnly()为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 ex2) {
					logger.error("Application exception overridden by commit exception", ex);
					throw ex2;
				}
				catch (Error err) {
					logger.error("Application exception overridden by commit error", ex);
					throw err;
				}
			}
		}
	}
  • a.首先是rollbackOn(ex)方法;该方法用于判断异常是否需要回滚,默认情况下方法实现为DefaultTransactionAttribute.rollbackOn(Throwable ex)方法;可以看到只有RuntimeException和Error才会回滚
  • @Override
    	public boolean rollbackOn(Throwable ex) {
    		return (ex instanceof RuntimeException || ex instanceof Error);
    	}
  • 我们可以通过@Transactional(rollbackFor = Exception.class,noRollbackFor = NoPermissionException.class)这种方式决定哪些异常回滚哪些异常不会滚;此时调用的方法是RuleBasedTransactionAttribute类的rollbackOn方法
  • b. 如果对于该异常需要回滚;方法被委托给事务管理器的rollback
  • c,如果是不需要回滚的异常,则提交事务;方法委托给事务管理器的commit方法

2.AbstractPlatformTransactionManager.rollback方法

/**
	 * This implementation of rollback handles participating in existing
	 * transactions. Delegates to {@code doRollback} and
	 * {@code doSetRollbackOnly}.
	 * @see #doRollback
	 * @see #doSetRollbackOnly
	 */
	@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(defStatus);
	}

	/**
	 * 处理实际的回滚
	 * 完成标识已经检查了
	 * @param status object representing the transaction
	 * @throws TransactionException in case of rollback failure
	 */
	private void processRollback(DefaultTransactionStatus status) {
		try {
			try {
				//触发所有注册的TransactionSynchronization的beforeCompletion方法,做些骚操作
				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 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");
				}
			}
			catch (RuntimeException ex) {
				triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
				throw ex;
			}
			catch (Error err) {
				triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
				throw err;
			}
			//回调TransactionSynchronization的afterCompletion方法
			triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);
		}
		finally {
			cleanupAfterCompletion(status);
		}
	}
  • a.trggerxxxxx方法:对于自定义TransactionSynchronization接口实现的调用:在回滚前,完成回滚,回滚出现异常情况下都会调用哎嘿嘿;我们可以通过
  • TransactionSynchronizationManager.registerSynchronization注册
  • b.当前事务信息中有没有保存点;如果有的话,使用SavepointManager回滚保存点;比如
  • @Override
    	public void rollbackToSavepoint(Object savepoint) throws TransactionException {
    		ConnectionHolder conHolder = getConnectionHolderForSavepoint();
    		try {
    			conHolder.getConnection().rollback((Savepoint) savepoint);
    		}
    		catch (Throwable ex) {
    			throw new TransactionSystemException("Could not roll back to JDBC savepoint", ex);
    		}
    	}
  • c.对于新事务,委托doRollback方法给不同的事务管理器比如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);
    		}
    	}
  • d.事务并不独立,判断下是否需要设置rollbackOnly标识
  • @Override
    	protected void doSetRollbackOnly(DefaultTransactionStatus status) {
    		DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
    		if (status.isDebug()) {
    			logger.debug("Setting JDBC transaction [" + txObject.getConnectionHolder().getConnection() +
    					"] rollback-only");
    		}
    		txObject.setRollbackOnly();
    	}
  • e.回滚后,清理事务信息归还占用的connection并唤醒挂起的资源
  • /**
    	 * 完成后清理,必要时清除同步,
    	 * 并调用doCleanupAfterCompletion
    	 * @param status object representing the transaction
    	 * @see #doCleanupAfterCompletion
    	 */
    	private void cleanupAfterCompletion(DefaultTransactionStatus status) {
    		//设置完成标识
    		status.setCompleted();
    		if (status.isNewSynchronization()) {
    			TransactionSynchronizationManager.clear();
    		}
    		//当前事务为新事务;解除资源与线程绑定 还原connection属性 并归还给连接池
    		if (status.isNewTransaction()) {
    			doCleanupAfterCompletion(status.getTransaction());
    		}
    		//当前事务挂起的资源不为Null
    		if (status.getSuspendedResources() != null) {
    			if (status.isDebug()) {
    				logger.debug("Resuming suspended transaction after completion of inner transaction");
    			}
    			//恢复挂起的资源
    			resume(status.getTransaction(), (SuspendedResourcesHolder) status.getSuspendedResources());
    		}
    	}
    
    @Override
    	protected void doCleanupAfterCompletion(Object transaction) {
    		//事务object
    		DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
    
    		// Remove the connection holder from the thread, if exposed.
    		// 解除数据库连接与当前事务的绑定
    		if (txObject.isNewConnectionHolder()) {
    			TransactionSynchronizationManager.unbindResource(this.dataSource);
    		}
    
    		// Reset connection.
    		// 释放连接
    		Connection con = txObject.getConnectionHolder().getConnection();
    		try {
    			if (txObject.isMustRestoreAutoCommit()) {
    				con.setAutoCommit(true);
    			}
    			DataSourceUtils.resetConnectionAfterTransaction(con, txObject.getPreviousIsolationLevel());
    		}
    		catch (Throwable ex) {
    			logger.debug("Could not reset JDBC Connection after transaction", ex);
    		}
    
    		if (txObject.isNewConnectionHolder()) {
    			if (logger.isDebugEnabled()) {
    				logger.debug("Releasing JDBC Connection [" + con + "] after transaction");
    			}
    			//释放连接
    			DataSourceUtils.releaseConnection(con, this.dataSource);
    		}
    
    		txObject.getConnectionHolder().clear();
    	}
        
    /**
    	 * Resume the given transaction. Delegates to the {@code doResume}
    	 * template method first, then resuming transaction synchronization.
    	 *
    	 * 恢复给定的事务。 首先委托{@code doResume}模板方法,然后恢复事务同步。
    	 * @param transaction the current transaction object
    	 * @param resourcesHolder the object that holds suspended resources,
    	 * as returned by {@code suspend} (or {@code null} to just
    	 * resume synchronizations, if any)
    	 * @see #doResume
    	 * @see #suspend
    	 */
    	protected final void resume(Object transaction, SuspendedResourcesHolder resourcesHolder)
    			throws TransactionException {
    		if (resourcesHolder != null) {
    			//挂起的资源
    			Object suspendedResources = resourcesHolder.suspendedResources;
    			if (suspendedResources != null) {
    				//模板方法留给子类实现
    				doResume(transaction, suspendedResources);
    			}
    			List<TransactionSynchronization> suspendedSynchronizations = resourcesHolder.suspendedSynchronizations;
    			if (suspendedSynchronizations != null) {
    				//恢复挂起的事务信息
    				TransactionSynchronizationManager.setActualTransactionActive(resourcesHolder.wasActive);
    				TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(resourcesHolder.isolationLevel);
    				TransactionSynchronizationManager.setCurrentTransactionReadOnly(resourcesHolder.readOnly);
    				TransactionSynchronizationManager.setCurrentTransactionName(resourcesHolder.name);
    				doResumeSynchronization(suspendedSynchronizations);
    			}
    		}
    	}
        

3.AbstractPlatformTransactionManager.commitTransactionAfterReturning方法提交事务方法

/**
	 * 成功完成调用后执行,但在处理异常后不执行。
	 * 如果我们没有创建事务,则不执行任何操作
	 * @param txInfo information about the current transaction
	 */
	protected void commitTransactionAfterReturning(TransactionInfo txInfo) {
		//事务信息不为null 并且包含事务
		if (txInfo != null && txInfo.hasTransaction()) {
			if (logger.isTraceEnabled()) {
				logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() + "]");
			}
			//委托给事务管理器提交事务
			txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
		}
	}

 委托commit方法给AbstractTransactionManager.commit()

/**
	 * commit方法的实现,处理参与已存在的事务并且程序化的回滚请求
	 * Delegates to {@code isRollbackOnly}, {@code doCommit}
	 * and {@code rollback}.
	 * @see org.springframework.transaction.TransactionStatus#isRollbackOnly()
	 * @see #doCommit
	 * @see #rollback
	 */
	@Override
	public final void commit(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");
		}

		//事务status
		DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
		//在嵌套事务中已被标记为回滚,回滚
		if (defStatus.isLocalRollbackOnly()) {
			if (defStatus.isDebug()) {
				logger.debug("Transactional code has requested rollback");
			}
			//事务回滚
			processRollback(defStatus);
			return;
		}
		//不应该在设置了globalRollbackOnly的情况下提交 并且 事务状态该需要回滚
		if (!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) {
			if (defStatus.isDebug()) {
				logger.debug("Global transaction is marked as rollback-only but transactional code requested commit");
			}
			//回滚操作
			processRollback(defStatus);
			// Throw UnexpectedRollbackException only at outermost transaction boundary
			// or if explicitly asked to.
			if (status.isNewTransaction() || isFailEarlyOnGlobalRollbackOnly()) {
				throw new UnexpectedRollbackException(
						"Transaction rolled back because it has been marked as rollback-only");
			}
			return;
		}
		//提交事务
		processCommit(defStatus);
	}

4.实际提交事务的处理逻辑processCommit

/**
	 * 实际提交事务的逻辑
	 * 仅回滚标志已被检查并应用.
	 * @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 {
				//TODO 扩展点 提交之前准备
				prepareForCommit(status);
				//调用TransactionSynchronization 的beforeCommit方法
				triggerBeforeCommit(status);
				//调用TransactionSynchronization beforeCompletion
				triggerBeforeCompletion(status);
				beforeCompletionInvoked = true;
				boolean globalRollbackOnly = false;
				//新事物 或者 需要在全局标记为rollback-only的情况下是否提前失败
				if (status.isNewTransaction() || isFailEarlyOnGlobalRollbackOnly()) {
					globalRollbackOnly = status.isGlobalRollbackOnly();
				}
				//事务有保存点
				if (status.hasSavepoint()) {
					if (status.isDebug()) {
						logger.debug("Releasing transaction savepoint");
					}
					//释放保存点
					status.releaseHeldSavepoint();
				}
				//是否为新事物
				else if (status.isNewTransaction()) {
					if (status.isDebug()) {
						logger.debug("Initiating transaction commit");
					}
					//提交事务
					doCommit(status);
				}
				// Throw UnexpectedRollbackException if we have a global rollback-only
				// marker but still didn't get a corresponding exception from commit.
				//如果我们只有全局回滚标记,则抛出UnexpectedRollbackException
				//但仍然没有从提交中获得相应的异常
				if (globalRollbackOnly) {
					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
				//doCommit失败后是否应该执行回滚操作
				if (isRollbackOnCommitFailure()) {
					doRollbackOnCommitException(status, ex);
				}
				else {
					triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
				}
				throw ex;
			}
			catch (RuntimeException ex) {
				if (!beforeCompletionInvoked) {
					triggerBeforeCompletion(status);
				}
				doRollbackOnCommitException(status, ex);
				throw ex;
			}
			catch (Error err) {
				if (!beforeCompletionInvoked) {
					triggerBeforeCompletion(status);
				}
				doRollbackOnCommitException(status, err);
				throw err;
			}

			// 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);
		}
	}
  • a.事务状态总有保存点,不提交事务;仅仅是releaseSavePoint()
  • /**
    	 * This implementation releases the given JDBC 3.0 Savepoint.
    	 * @see java.sql.Connection#releaseSavepoint
    	 */
    	@Override
    	public void releaseSavepoint(Object savepoint) throws TransactionException {
    		ConnectionHolder conHolder = getConnectionHolderForSavepoint();
    		try {
    			conHolder.getConnection().releaseSavepoint((Savepoint) savepoint);
    		}
    		catch (Throwable ex) {
    			logger.debug("Could not explicitly release JDBC savepoint", ex);
    		}
    	}
  • b.真正提交事务的代码,交给了子类实现DataSourceTransactionManager.doCommit,可以看到最终还是基于connection提交了事务
  • @Override
    	protected void doCommit(DefaultTransactionStatus status) {
    		DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
    		Connection con = txObject.getConnectionHolder().getConnection();
    		if (status.isDebug()) {
    			logger.debug("Committing JDBC transaction on Connection [" + con + "]");
    		}
    		try {
    			con.commit();
    		}
    		catch (SQLException ex) {
    			throw new TransactionSystemException("Could not commit JDBC transaction", ex);
    		}
    	}
  • c.提交失败了Spring对TransactionException 、RuntimeException、Error、类型的异常会进行事务回滚;真的是贴心呢。
private void doRollbackOnCommitException(DefaultTransactionStatus status, Throwable ex) throws TransactionException {
		try {
			if (status.isNewTransaction()) {
				if (status.isDebug()) {
					logger.debug("Initiating transaction rollback after commit exception", ex);
				}
				doRollback(status);
			}
			else if (status.hasTransaction() && isGlobalRollbackOnParticipationFailure()) {
				if (status.isDebug()) {
					logger.debug("Marking existing transaction as rollback-only after commit exception", ex);
				}
				doSetRollbackOnly(status);
			}
		}
		catch (RuntimeException rbex) {
			logger.error("Commit exception overridden by rollback exception", ex);
			triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
			throw rbex;
		}
		catch (Error rberr) {
			logger.error("Commit exception overridden by rollback exception", ex);
			triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
			throw rberr;
		}
		triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);
	}

5.清楚当前线程绑定的事务信息

/**
	 * 重置TransactionInfo ThreadLocal。
	 * <p>在所有情况下都要调用它:异常或正常返回!
	 * @param txInfo information about the current transaction (may be {@code null})
	 */
	protected void cleanupTransactionInfo(TransactionInfo txInfo) {
		if (txInfo != null) {
			txInfo.restoreThreadLocalStatus();
		}
	}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值