Spring如何实现的事务控制

830 阅读5分钟

1 准备知识

1.1 JDBC处理事务

事务的处理,就是先关闭Connection的AutoCommit,执行完业务操作后,再手动commit或rollback。

Connection con = ...
// 关闭自动提交
con.setAutoCommit(false);
// 业务处理
aDao.insert(...);
bDao.insert(...);
try{
    // 提交
    con.commit();
}catch (Exception e){
    // 回滚
    con.rollback();
}
// 恢复自动提交
con.setAutoCommit(true);

1.2 Spring的AOP

在Spring的AOP代理类JdkDynamicAopProxyObjenesisCglibAopProxy中增加方法的时候,有下面几个步骤:

  • 1 调用DefaultAdvisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice获取一个org.aopalliance.intercept.MethodInterceptor的list;
  • 2 用这个MethodInterceptor的list创建ReflectiveMethodInvocation对象,并调用proceed()方法;
  • 3 TransactionInterceptor是list其中的一个MethodInterceptor,用来执行事务。

有关Spring AOP具体实现可以查看 Spring AOP源码实现分步解析

2 Spring事务控制

  • Spring的事务控制,就是利用AOP,在业务方法执行前通过DataSource拿到Connection,然后setAutoCommit(false);业务方法执行完后再commit或rollback。
  • 事务处理在TransactionInterceptor.invoke中进行;
  • TransactionInterceptor调用里父类TransactionAspectSupport的invokeWithinTransaction方法进行具体的事务控制。

2.1 几个重要的类

2.1.1 TransactionAttribute

事务属性,TransactionDefinition的子类

  • TransactionDefinition默认实现类DefaultTransactionDefinition
  • TransactionAttribute的实现类都继承了DefaultTransactionDefinition;
  • TransactionDefinition定义事务相关属性:
// 事务传播模式
int PROPAGATION_REQUIRED = 0;
int PROPAGATION_SUPPORTS = 1;
int PROPAGATION_MANDATORY = 2;
int PROPAGATION_REQUIRES_NEW = 3;
int PROPAGATION_NOT_SUPPORTED = 4;
int PROPAGATION_NEVER = 5;
int PROPAGATION_NESTED = 6;

// 事务隔离级别,使用java.sql.Connection.TRANSACTION*定义
int ISOLATION_DEFAULT = -1; // 默认,使用数据库的隔离级别
int ISOLATION_READ_UNCOMMITTED = Connection.TRANSACTION_READ_UNCOMMITTED; //读未提交
int ISOLATION_READ_COMMITTED = Connection.TRANSACTION_READ_COMMITTED; // 读已提交
int ISOLATION_REPEATABLE_READ = Connection.TRANSACTION_REPEATABLE_READ; // 可重复读
int ISOLATION_SERIALIZABLE = Connection.TRANSACTION_SERIALIZABLE; // 序列化
  • DefaultTransactionDefinition的主要属性:
	private int propagationBehavior = PROPAGATION_REQUIRED; // 事务传播方式
	private int isolationLevel = ISOLATION_DEFAULT; // 事务隔离级别
	private int timeout = TIMEOUT_DEFAULT; // 超时时间
  • 实现类:
    • RuleBasedTransactionAttribute
    • DefaultTransactionAttribute

2.1.2 PlatformTransactionManager

事务管理器

  • 方法:
    • TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException; // 根据TransactionDefinition创建TransactionStatus
    • void commit(TransactionStatus status) throws TransactionException; // 提交
    • void rollback(TransactionStatus status) throws TransactionException; // 回滚
  • 实现类:
    • DataSourceTransactionManager
    • AbstractPlatformTransactionManager

2.1.3 TransactionStatus

事务状态的操作类

  • SavepointManager的子类
  • 各种状态及Savepoint的创建/回滚/释放等
  • 实现类:
    • AbstractTransactionStatus
    • DefaultTransactionStatus

2.1.4 TransactionInfo

  • 事务信息的类,包括事务管理器,事务属性等;
  • 通过createTransactionIfNecessary创建;
  • 重要属性:
    • PlatformTransactionManager
    • TransactionAttribute
    • joinpointIdentification : 切入方法,如com.xx.yy.MockService.mockInsert
    • TransactionStatus

2.2 事务执行过程

2.2.1 invokeWithinTransaction

invokeWithinTransaction是执行事务的主流程

protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
			final InvocationCallback invocation) throws Throwable {

        // 1. 获取事务属性,没有则表示当前不在事务中
		/*
		  TransactionAttributeSource: 事务属性源,用来获取事务属性,如 org.springframework.transaction.annotation.AnnotationTransactionAttributeSource
		  TransactionAttribute:事务属性,如 org.springframework.transaction.interceptor.RuleBasedTransactionAttribute
		*/ 
		TransactionAttributeSource tas = getTransactionAttributeSource();
		final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
		
		// 2. 获取PlatformTransactionManager,如DataSourceTransactionManager。
		final PlatformTransactionManager tm = determineTransactionManager(txAttr);
		
		// 3. 待执行的切入方法,如 com.xx.yy.MockService.mockInsert
		final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);

		if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
		     
		   // 4.事务不存在或不是编程式事务,则尝试创建或获取事务,并执行commit/rollback等。
			TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
			Object retVal = null;
			try {
				// This is an around advice: Invoke the next interceptor in the chain.
				// This will normally result in a target object being invoked.
				// 5 执行业务代码 即service中的方法
				retVal = invocation.proceedWithInvocation();
			}
			catch (Throwable ex) {
				// 回滚,如果有SavePoint,则回滚到SavePoint。
				completeTransactionAfterThrowing(txInfo, ex);
				throw ex;
			}
			finally {
				cleanupTransactionInfo(txInfo);
			}
			// 6 执行Connection.commit()
			commitTransactionAfterReturning(txInfo);
			return retVal;
		}

		else {
		    // TransactionTemplate.execute中使用TransactionCallback进行的回调式的事务处理
			// 省略代码
		}
	}

2.2.2 创建TransactionAttribute

ProxyTransactionManagementConfiguration在创建TransactionInterceptor的Bean时,通过new AnnotationTransactionAttributeSource()创建了TransactionAttributeSource,并设置到interceptor中。

AnnotationTransactionAttributeSource.getTransactionAttribute经多层调用,最终调用到determineTransactionAttribute方法,使用SpringTransactionAnnotationParser解析AnnotatedElement;

SpringTransactionAnnotationParser.parseTransactionAnnotation:

  • AnnotatedElementUtils.findMergedAnnotationAttributes将AnnotabledElement及Transactional解析为AnnotationAttributes;
  • 解析AnnotationAttributes,设置传播类型,隔离级别等。返回RuleBasedTransactionAttribute。
protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {
		RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();
		Propagation propagation = attributes.getEnum("propagation");
		rbta.setPropagationBehavior(propagation.value());
		Isolation isolation = attributes.getEnum("isolation");
		rbta.setIsolationLevel(isolation.value());
		rbta.setTimeout(attributes.getNumber("timeout").intValue());
		rbta.setReadOnly(attributes.getBoolean("readOnly"));
		rbta.setQualifier(attributes.getString("value"));
		ArrayList<RollbackRuleAttribute> rollBackRules = new ArrayList<>();
		Class<?>[] rbf = attributes.getClassArray("rollbackFor");
		for (Class<?> rbRule : rbf) {
			RollbackRuleAttribute rule = new RollbackRuleAttribute(rbRule);
			rollBackRules.add(rule);
		}
		String[] rbfc = attributes.getStringArray("rollbackForClassName");
		for (String rbRule : rbfc) {
			RollbackRuleAttribute rule = new RollbackRuleAttribute(rbRule);
			rollBackRules.add(rule);
		}
		Class<?>[] nrbf = attributes.getClassArray("noRollbackFor");
		for (Class<?> rbRule : nrbf) {
			NoRollbackRuleAttribute rule = new NoRollbackRuleAttribute(rbRule);
			rollBackRules.add(rule);
		}
		String[] nrbfc = attributes.getStringArray("noRollbackForClassName");
		for (String rbRule : nrbfc) {
			NoRollbackRuleAttribute rule = new NoRollbackRuleAttribute(rbRule);
			rollBackRules.add(rule);
		}
		rbta.getRollbackRules().addAll(rollBackRules);
		return rbta;
	}

2.2.3 获取PlatformTransactionManager

  • PlatformTransactionManager已经在系统启动时声明为Bean;
  • determineTransactionManager方法中,通过defaultTransactionManager = this.beanFactory.getBean(PlatformTransactionManager.class);获取。

2.2.4 创建TransactionInfo

TransactionInfo对象在TransactionAspectSupport.createTransactionIfNecessary中创建:

  • 通过PlatformTransactionManager.getTransaction创建TransactionStatus;
  • 用创建的TransactionStatus和其他属性,通过prepareTransactionInfo方法创建TransactionInfo对象。
    // 创建TransactionInfo
    protected TransactionInfo prepareTransactionInfo(@Nullable PlatformTransactionManager tm,
			@Nullable TransactionAttribute txAttr, String joinpointIdentification,
			@Nullable TransactionStatus status) {

		TransactionInfo txInfo = new TransactionInfo(tm, txAttr, joinpointIdentification);
		if (txAttr != null) {
			// We need a transaction for this method...
			if (logger.isTraceEnabled()) {
				logger.trace("Getting transaction for [" + txInfo.getJoinpointIdentification() + "]");
			}
			// The transaction manager will flag an error if an incompatible tx already exists.
			txInfo.newTransactionStatus(status);
		}
		else {
			// The TransactionInfo.hasTransaction() method will return false. We created it only
			// to preserve the integrity of the ThreadLocal stack maintained in this class.
			if (logger.isTraceEnabled())
				logger.trace("Don't need to create transaction for [" + joinpointIdentification +
						"]: This method isn't transactional.");
		}

		// We always bind the TransactionInfo to the thread, even if we didn't create
		// a new transaction here. This guarantees that the TransactionInfo stack
		// will be managed correctly even if no transaction was created by this aspect.
		/*
		将TransactionStatus绑定到当前ThreadLocal中,并备份旧的TransactionStatus。
		*/
		txInfo.bindToThread();
		return txInfo;
	}

2.2.5 创建TransactionStatus

由AbstractPlatformTransactionManager.getTransaction创建

public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException {
        
        /* 
        1. 获取 DataSourceTransactionObject;
           DataSourceTransactionManager.doGetTransaction方法中如果允许嵌套事务,则允许设置Savepoint,以支持嵌套事务.
        */
		Object transaction = doGetTransaction();

		// Cache debug flag to avoid repeated checks.
		boolean debugEnabled = logger.isDebugEnabled();

		if (definition == null) {
			// 2. 如果前面没有创建TransactionAttribute(TransactionDefinition的子类),则这里创建一个默认值的DefaultTransactionDefinition。
			definition = new DefaultTransactionDefinition();
		}

        // 事务是否存在,通过DataSourceTransactionObject.txObject.getConnectionHolder().isTransactionActive()判断
		if (isExistingTransaction(transaction)) {
			/*
			 3. 如果存在,则根据definition.getPropagationBehavior()进行不同处理:
			 (1) PROPAGATION_NEVER : throw new IllegalTransactionStateException
			 (2) PROPAGATION_NOT_SUPPORTED : 挂起当前事务,最终是执行了doSuspend方法,对DataSourceTransactionObject执行setConnectionHolder(null),并解绑DataSource。
			 (3) PROPAGATION_REQUIRES_NEW : 挂起当前事务,创建新的DefaultTransactionStatus,并指定doBegin方法。即创建新的事务。
			 (4) PROPAGATION_NESTED: 如果nestedTransactionAllowed==false(默认是false,开启需要手动指定),则throw new NestedTransactionNotSupportedException。
			                         创建新的DefaultTransactionStatus,并执行createAndHoldSavepoint()创建SavePoint。
			*/
			return handleExistingTransaction(definition, transaction, debugEnabled);
		}

        // 以下是事务不存在的处理
		if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
			throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout());
		}

		// 传播行为是PROPAGATION_MANDATORY,根据行为定义,则需要抛出异常。
		if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
			throw new IllegalTransactionStateException(
					"No existing transaction found for transaction marked with propagation 'mandatory'");
		}
		else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
				definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
				definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
			SuspendedResourcesHolder suspendedResources = suspend(null);
			if (debugEnabled) {
				logger.debug("Creating new transaction with name [" + definition.getName() + "]: " + definition);
			}
			try {
				boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
				DefaultTransactionStatus status = newTransactionStatus(
						definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
				// 执行 setAutoCommit等
				doBegin(transaction, definition);
				prepareSynchronization(status, definition);
				return status;
			}
			catch (RuntimeException | Error ex) {
				resume(null, suspendedResources);
				throw ex;
			}
		}
		else {
			// Create "empty" transaction: no actual transaction, but potentially synchronization.
			if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) {
				logger.warn("Custom isolation level specified but no actual transaction initiated; " +
						"isolation level will effectively be ignored: " + definition);
			}
			boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
			return prepareTransactionStatus(definition, null, true, newSynchronization, debugEnabled, null);
		}
	}

2.2.6 doBegin

DataSourceTransactionManager.doBegin

protected void doBegin(Object transaction, TransactionDefinition definition) {
		DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
		Connection con = null;

		try {
			if (!txObject.hasConnectionHolder() ||
					txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
				// 1. 从DataSource中获取Connection
				Connection newCon = obtainDataSource().getConnection();
				if (logger.isDebugEnabled()) {
					logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
				}
				// 2. 设置ConnectionHolder 以备后面使用
				txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
			}

			txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
			// 3. 获取Connection
			con = txObject.getConnectionHolder().getConnection();

			Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
			// 4. 设置Connection的readOnly和transactionIsolation(事务隔离级别)。
			txObject.setPreviousIsolationLevel(previousIsolationLevel);

			if (con.getAutoCommit()) {
			    // 执行完后必须恢复AutoCommit
				txObject.setMustRestoreAutoCommit(true);
				if (logger.isDebugEnabled()) {
					logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
				}
				// 4. 禁止AutoCommit
				con.setAutoCommit(false);
			}

            // prepareTransactionalConnection方法中,如果是(isEnforceReadOnly() && definition.isReadOnly()),会执行`stmt.executeUpdate("SET TRANSACTION READ ONLY");`
			prepareTransactionalConnection(con, definition);
			txObject.getConnectionHolder().setTransactionActive(true);

			int timeout = determineTimeout(definition);
			if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
				txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
			}

			// Bind the connection holder to the thread.
			if (txObject.isNewConnectionHolder()) {
				TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());
			}
		}

		catch (Throwable ex) {
			if (txObject.isNewConnectionHolder()) {
				DataSourceUtils.releaseConnection(con, obtainDataSource());
				txObject.setConnectionHolder(null, false);
			}
			throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);
		}
	}