Spring 事务处理

267 阅读15分钟

概述

我们通常在项目中使用事务,只需要增加一个 @Transactional 注解就可以正常使用事务定义。我们有去思考过这个注解的含义以及背后的原理吗?本文将从Spring 事务核心,@Transactional 注解工作原理,事务的传播机制等三个方面进行详细阐述。

Spring 事务核心

Spring 事务处理方式分为两种:编程式事务,申明式事务。我们常用的注解的方式也是申明式事务,如果我们通过手动去开启事务,正常完成进行 commit 异常进行 fallback 这种就是编程式事务。我们主要描述申明式事务的实现

启用事务管理

  1. @EnableTransactionManagement 定义如下,在这了加载一个 TransactionManagementConfigurationSelector
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
	// ...
}
  1. TransactionManagementConfigurationSelector 是一个 ImportSelector 加载了两个类 AutoProxyRegistrar 和 ProxyTransactionManagementConfiguration 。
@Override
protected String[] selectImports(AdviceMode adviceMode) {
    switch (adviceMode) {
        case PROXY:
            //向 Spring 中添加了 AutoProxyRegistrar 和 ProxyTransactionManagementConfiguration 对应的 bean
            return new String[] {AutoProxyRegistrar.class.getName(),
                    ProxyTransactionManagementConfiguration.class.getName()};
        case ASPECTJ:
            return new String[] {determineTransactionAspectClass()};
        default:
            return null;
    }
}

3.AutoProxyRegistrar 其实是一个自动代理创建器

- AutoProxyRegistrar#registerBeanDefinitions()
  // 注册自动代理创建器
  -- AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
  // 注册一个 InfrastructureAdvisorAutoProxyCreator 其实它也是实现了 BeanPostProcessor
  -- registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source);
  1. ProxyTransactionManagementConfiguration 其实是一个代理逻辑 Advisor 包含了 PoincutAdvice
@Configuration
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {

	@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {

		BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
		//表示切点
		advisor.setTransactionAttributeSource(transactionAttributeSource());
		//表示 advice 代理逻辑
		advisor.setAdvice(transactionInterceptor());
		if (this.enableTx != null) {
			advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
		}
		return advisor;
	}

	// TransactionAttributeSource 表示 @Transaction 所包含的信息
	@Bean
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public TransactionAttributeSource transactionAttributeSource() {
		return new AnnotationTransactionAttributeSource();
	}

	// TransactionInterceptor 这里其实是一个代理的逻辑的细节 
	@Bean
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public TransactionInterceptor transactionInterceptor() {
		TransactionInterceptor interceptor = new TransactionInterceptor();
		//拦截器中持有的 @Transaction 注解信息
		interceptor.setTransactionAttributeSource(transactionAttributeSource());
		if (this.txManager != null) {
			interceptor.setTransactionManager(this.txManager);
		}
		return interceptor;
	}

}

// TransactionInterceptor 类
public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {

    // ...
    
    @Override
    @Nullable
    public Object invoke(MethodInvocation invocation) throws Throwable {
        // Work out the target class: may be {@code null}.
        // The TransactionAttributeSource should be passed the target class
        // as well as the method, which may be from an interface.
        Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);

        // Adapt to TransactionAspectSupport's invokeWithinTransaction...
        // 执行代理逻辑
        return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
    }
}

// BeanFactoryTransactionAttributeSourceAdvisor 中定义 
public class BeanFactoryTransactionAttributeSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor {
    // 构造了一个 Pointcut, TransactionAttributeSource 的实现对象为 AnnotationTransactionAttributeSource
    // 在 Pointcut 匹配类时, 会利用 AnnotationTransactionAttributeSource 去检查类上是否有 @Transaction 注解
    // 在 Pointcut 匹配方法时, 会利用 AnnotationTransactionAttributeSource 去检查方法上是否有 @Transaction 注解
    private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {
        @Override
        @Nullable
        protected TransactionAttributeSource getTransactionAttributeSource() {
            return transactionAttributeSource;
        }
    };
    
    @Override
    public Pointcut getPointcut() {
        return this.pointcut;
    }
}

// TransactionAttributeSourcePointcut#matches 进行匹配方法/类上面是否包含 @Transaction 注解
abstract class TransactionAttributeSourcePointcut@ extends StaticMethodMatcherPointcut implements Serializable {

    /**
     * 判断 某个方法或者类 是否存在 @Transaction 注解
     * @param method the candidate method
     * @param targetClass the target class
     * @return
     */
    @Override
    public boolean matches(Method method, Class<?> targetClass) {
        if (TransactionalProxy.class.isAssignableFrom(targetClass) ||
                PlatformTransactionManager.class.isAssignableFrom(targetClass) ||
                PersistenceExceptionTranslator.class.isAssignableFrom(targetClass)) {
            return false;
        }
        TransactionAttributeSource tas = getTransactionAttributeSource();
        //某个类或者方法上是否存在 @Transaction 注解
        //调用 AnnotationTransactionAttributeSource 的父类中的 getTransactionAttribute 方法
        //按段是否有 @Transaction 注解, 获取到注解信息不等于 null 则匹配
        return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
    }
}    

//tas.getTransactionAttribute(method, targetClass)
@Override
@Nullable
public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
    if (method.getDeclaringClass() == Object.class) {
        return null;
    }

    // First, see if we have a cached value.
    Object cacheKey = getCacheKey(method, targetClass);
    TransactionAttribute cached = this.attributeCache.get(cacheKey);
    if (cached != null) {
        // Value will either be canonical value indicating there is no transaction attribute,
        // or an actual transaction attribute.
        if (cached == NULL_TRANSACTION_ATTRIBUTE) {
            return null;
        }
        else {
            return cached;
        }
    }
    else {
        // We need to work it out.
        // 获取 @Transactional 注解信息
        TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass);
        // Put it in the cache.
        if (txAttr == null) {
            this.attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE);
        }
        else {
            String methodIdentification = ClassUtils.getQualifiedMethodName(method, targetClass);
            if (txAttr instanceof DefaultTransactionAttribute) {
                ((DefaultTransactionAttribute) txAttr).setDescriptor(methodIdentification);
            }
            if (logger.isTraceEnabled()) {
                logger.trace("Adding transactional method '" + methodIdentification + "' with attribute: " + txAttr);
            }
            this.attributeCache.put(cacheKey, txAttr);
        }
        return txAttr;
    }
}

//computeTransactionAttribute(method, targetClass);
protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
    // Don't allow no-public methods as required.
    // allowPublicMethodsOnly 默认为 false, 所以在 public 方法上写上 @Transactional 注解没有作用
    if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
        return null;
    }

    // The method may be on an interface, but we need attributes from the target class.
    // If the target class is null, the method will be unchanged.
    Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);

    // First try is the method in the target class.
    TransactionAttribute txAttr = findTransactionAttribute(specificMethod);
    if (txAttr != null) {
        return txAttr;
    }

    // Second try is the transaction attribute on the target class.
    txAttr = findTransactionAttribute(specificMethod.getDeclaringClass());
    if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
        return txAttr;
    }

    if (specificMethod != method) {
        // Fallback is to look at the original method.
        txAttr = findTransactionAttribute(method);
        if (txAttr != null) {
            return txAttr;
        }
        // Last fallback is the class of the original method.
        txAttr = findTransactionAttribute(method.getDeclaringClass());
        if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
            return txAttr;
        }
    }

    return null;
}

其实到这里可以得到一个结论:
@Transactional 注解对 public 方法才有效,其它的方法是无效的

TransactionInterceptor 对事务方法的执行

  1. TransactionInterceptor invoke 方法是事务执行的核心方法
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
    final InvocationCallback invocation) throws Throwable {

    // If the transaction attribute is null, the method is non-transactional.
    TransactionAttributeSource tas = getTransactionAttributeSource();
    // 获取得到当前方法或者类上的 @Transactional 注解的信息
    final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
    // 得到一个 @Transactional 注解的信息
    final PlatformTransactionManager tm = determineTransactionManager(txAttr);
    // 根据当前执行的类中的某个方法以及 @Transactional 注解的信息生成一个唯一的标示, 这个标示会用来作为事务的名称
    final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);

    if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
        // Standard transaction demarcation with getTransaction and commit/rollback calls.
        // 创建事务,并且得到当前事务的信息,后面需要事务信息来进行提交或者回滚
        // 例如: cn.edu.xxx.tx.service.PersonService.test
        // 这里默认就是 类名全路径 + 方法名
        TransactionInfo txInfo = createTransactionIfNecessary(tm, 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
            // 出现异常的清隽管辖,如果是异常需要 rollback , 否则就提交
            completeTransactionAfterThrowing(txInfo, ex);
            // 出现了异常限制性 finally 中的逻辑再抛出异常
            throw ex;
        }
        finally {
            //删除事务
            cleanupTransactionInfo(txInfo);
        }
        //提交事务
        commitTransactionAfterReturning(txInfo);
        return retVal;
    }

    else {
        final ThrowableHolder throwableHolder = new ThrowableHolder();

        // It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
        try {
            Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr, status -> {
                TransactionInfo txInfo = prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
                try {
                    return invocation.proceedWithInvocation();
                }
                catch (Throwable ex) {
                    if (txAttr.rollbackOn(ex)) {
                        // A RuntimeException: will lead to a rollback.
                        if (ex instanceof RuntimeException) {
                            throw (RuntimeException) ex;
                        }
                        else {
                            throw new ThrowableHolderException(ex);
                        }
                    }
                    else {
                        // A normal return value: will lead to a commit.
                        throwableHolder.throwable = ex;
                        return null;
                    }
                }
                finally {
                    cleanupTransactionInfo(txInfo);
                }
            });

            // Check result state: It might indicate a Throwable to rethrow.
            if (throwableHolder.throwable != null) {
                throw throwableHolder.throwable;
            }
            return result;
        }
        catch (ThrowableHolderException ex) {
            throw ex.getCause();
        }
        catch (TransactionSystemException ex2) {
            if (throwableHolder.throwable != null) {
                logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
                ex2.initApplicationException(throwableHolder.throwable);
            }
            throw ex2;
        }
        catch (Throwable ex2) {
            if (throwableHolder.throwable != null) {
                logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
            }
            throw ex2;
        }
    }
}
  1. completeTransactionAfterThrowing(txInfo, ex); 异常处理, 这里会判断是 RuntimeException 或者 Error 会进行回滚,其它的事务不会进行回滚。
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);
        }
        // 如果当前异常需要回滚,就执行回滚操作,否则提交
        // 默认是 RuntimeException 或者 Error
        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;
            }
        }
    }
}

  1. 通过这个方法我们可以看出我们在使用过程中首先要创建一个 PlatformTransactionManager
@Bean
public DataSourceTransactionManager transactionManager() {
    return new DataSourceTransactionManager(dataSource());
}
  1. 事务的获取 TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,
        @Nullable TransactionAttribute txAttr, final String joinpointIdentification) {

    // If no name specified, apply method identification as transaction name.
    // 事务名称
    if (txAttr != null && txAttr.getName() == null) {
        txAttr = new DelegatingTransactionAttribute(txAttr) {
            @Override
            public String getName() {
                return joinpointIdentification;
            }
        };
    }
    // 事务对象状态
    TransactionStatus status = null;
    if (txAttr != null) {
        if (tm != null) {
            status = tm.getTransaction(txAttr);
        }
        else {
            if (logger.isDebugEnabled()) {
                logger.debug("Skipping transactional joinpoint [" + joinpointIdentification +
                        "] because no transaction manager has been configured");
            }
        }
    }
    return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
}
  1. 我们在来看如何去获取事务 tm.getTransaction(txAttr)
public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException {
    Object transaction = doGetTransaction(); //获取事务对象,每次都会生成一个 DataSourceTransactionObject 事务对象 connectionHolder 默认为空

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

    if (definition == null) {
        // Use defaults if no transaction definition given.
        definition = new DefaultTransactionDefinition();
    }

    if (isExistingTransaction(transaction)) {  //如果已经存在一个数据库链接说明存在一个事务
        // Existing transaction found -> check propagation behavior to find out how to behave.
        return handleExistingTransaction(definition, transaction, debugEnabled); //存在事务的情况下,按照不同的传播级别进行处理
    }

    // Check definition settings for new transaction.
    if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
        throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout());
    }

    // No existing transaction found -> check propagation behavior to find out how to proceed.
    // 事务不存在
    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);

            // 事务对象中包括:
            // 1.事务的定义
            // 2.事务对象
            // 3.是否是新事务
            DefaultTransactionStatus status = newTransactionStatus(
                    definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
            // 开启新事务,获取新的连接对象
            doBegin(transaction, definition);
            // 初始化 TransactionSynchronizationManager 中的属性
            prepareSynchronization(status, definition);
            return status;
        }
        catch (RuntimeException | Error ex) {
            resume(null, suspendedResources);
            throw ex;
        }
    }
    else {
        // 不会 doBegin, 不会真的开启事务, 也就是不会把 Connection 的 autoCommint 设置为 false , sql 没有在事务中执行
        // 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);
    }
}
  1. 我们再来看 doBegin 是如何开启一个事务的
protected void doBegin(Object transaction, TransactionDefinition definition) {
    DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
    Connection con = null;

    try {
        // 如果事务对象内没有链接就从 dataSource 中获取一个链接
        if (!txObject.hasConnectionHolder() ||
                txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
            // isSynchronizedWithTransaction 表示是否和事务通过, 表示一个事务就从 dataSource 中获取一个链接
            // 默认是false 所以在事务开启时,除非当前事务对象中没有链接才会去 dataSource 中获取一个链接
            Connection newCon = obtainDataSource().getConnection();
            if (logger.isDebugEnabled()) {
                logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
            }
            txObject.setConnectionHolder(new ConnectionHolder(newCon), true); // 设置 newConnectionHolder 为 true
        }

        txObject.getConnectionHolder().setSynchronizedWithTransaction(true);//如果在事务开启时, 事务对象就已经有事务链接了
        con = txObject.getConnectionHolder().getConnection();

        Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);//设置数据库链接的隔离级别, 如果当前事务中的隔离级别和数据库的隔离级别不一样就返回数据库的隔离级别并且记录下来,事务结束后恢复
        txObject.setPreviousIsolationLevel(previousIsolationLevel);

        // Switch to manual commit if necessary. This is very expensive in some JDBC drivers,
        // so we don't want to do it unnecessarily (for example if we've explicitly
        // configured the connection pool to set it already).
        if (con.getAutoCommit()) {
            txObject.setMustRestoreAutoCommit(true);
            if (logger.isDebugEnabled()) {
                logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
            }
            con.setAutoCommit(false); //把数据库链接 autocommit  设置为 false
        }

        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()) {
            //把新生成的数据库链接设置到当前线程的 ThreadLocal 缓存
            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);
    }
}
  1. handleExistingTransaction 如果当前事务存在那么就通过事务的传播机制进行判断后续的处理
private TransactionStatus handleExistingTransaction(
        TransactionDefinition definition, Object transaction, boolean debugEnabled)
        throws TransactionException {

    if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {
        throw new IllegalTransactionStateException(
                "Existing transaction found for transaction marked with propagation 'never'");
    }

    // 当前存在的事务, 则把当前的事务挂起,以非事务的方式执行
    if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
        if (debugEnabled) {
            logger.debug("Suspending current transaction");
        }
        Object suspendedResources = suspend(transaction);
        boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
        return prepareTransactionStatus(
                definition, null, false, newSynchronization, debugEnabled, suspendedResources);
    }

    if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
        if (debugEnabled) {
            logger.debug("Suspending current transaction, creating new transaction with name [" +
                    definition.getName() + "]");
        }
        SuspendedResourcesHolder suspendedResources = suspend(transaction);
        try {
            boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
            DefaultTransactionStatus status = newTransactionStatus(
                    definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
            doBegin(transaction, definition);
            prepareSynchronization(status, definition);
            return status;
        }
        catch (RuntimeException | Error beginEx) {
            resumeAfterBeginException(transaction, suspendedResources, beginEx);
            throw beginEx;
        }
    }

    if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
        if (!isNestedTransactionAllowed()) {
            throw new NestedTransactionNotSupportedException(
                    "Transaction manager does not allow nested transactions by default - " +
                    "specify 'nestedTransactionAllowed' property with value 'true'");
        }
        if (debugEnabled) {
            logger.debug("Creating nested transaction with name [" + definition.getName() + "]");
        }
        if (useSavepointForNestedTransaction()) {
            // Create savepoint within existing Spring-managed transaction,
            // through the SavepointManager API implemented by TransactionStatus.
            // Usually uses JDBC 3.0 savepoints. Never activates Spring synchronization.
            DefaultTransactionStatus status =
                    prepareTransactionStatus(definition, transaction, false, false, debugEnabled, null);
            status.createAndHoldSavepoint();
            return status;
        }
        else {
            // Nested transaction through nested begin and commit/rollback calls.
            // Usually only for JTA: Spring synchronization might get activated here
            // in case of a pre-existing JTA transaction.
            boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
            DefaultTransactionStatus status = newTransactionStatus(
                    definition, transaction, true, newSynchronization, debugEnabled, null);
            doBegin(transaction, definition);
            prepareSynchronization(status, definition);
            return status;
        }
    }

    // Assumably PROPAGATION_SUPPORTS or PROPAGATION_REQUIRED.
    if (debugEnabled) {
        logger.debug("Participating in existing transaction");
    }
    if (isValidateExistingTransaction()) {
        if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) {
            Integer currentIsolationLevel = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel();
            if (currentIsolationLevel == null || currentIsolationLevel != definition.getIsolationLevel()) {
                Constants isoConstants = DefaultTransactionDefinition.constants;
                throw new IllegalTransactionStateException("Participating transaction with definition [" +
                        definition + "] specifies isolation level which is incompatible with existing transaction: " +
                        (currentIsolationLevel != null ?
                                isoConstants.toCode(currentIsolationLevel, DefaultTransactionDefinition.PREFIX_ISOLATION) :
                                "(unknown)"));
            }
        }
        if (!definition.isReadOnly()) {
            if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
                throw new IllegalTransactionStateException("Participating transaction with definition [" +
                        definition + "] is not marked as read-only but existing transaction is");
            }
        }
    }
    // 如果其它的值则在当前的事务运行
    boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
    return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);
}

TransactionSynchronizationManager 事务同步管理器

  1. 当事务启动完成后就对事务状态进行同步到事务管理器中,其实他的本质就是把当前事务信息存储到ThreadLocal 中进行管理,调用方法 prepareSynchronization(status, definition);
protected void prepareSynchronization(DefaultTransactionStatus status, TransactionDefinition definition) {
    if (status.isNewSynchronization()) {
        TransactionSynchronizationManager.setActualTransactionActive(status.hasTransaction());
        TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(
                definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT ?
                        definition.getIsolationLevel() : null);
        TransactionSynchronizationManager.setCurrentTransactionReadOnly(definition.isReadOnly());
        TransactionSynchronizationManager.setCurrentTransactionName(definition.getName());
        TransactionSynchronizationManager.initSynchronization();
    }
}
  1. 事务的回滚.首先进行事务同步器的同步, 然后判断是否有安全点 savepoint 如果有就回退到安全点。但是mysql是没有 savepoint 的回滚实现的。
private void processRollback(DefaultTransactionStatus status, boolean unexpected) {
    try {
        boolean unexpectedRollback = unexpected;

        try {
            //如果有同步器的 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 {
                // 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);
    }
}

@Transactional 注解使用

@Transactional 的使用方法,定义在方法上,表示方法上有事务,我们可以通过 propagation 属性来定义事务的传播机制

@Transactional
public void test() {
    userMapper.insert(user);

    userService.a();
}

@Transactional(propagation = Propagation.REQUIRED)
public void a() {
    userMapper.insert(user);
}

执行过程描述:

  1. 生成test事务状态对象
  2. test事务doBegin,获取并将数据库连接2825设置到test事务状态对象中
  3. 把test事务信息设置到事务同步管理器中
  4. 执行test业务逻辑方法(可以获取到test事务的信息)
    4.1. 生成a事务状态对象,并且可以获取到当前线程中已经存在的数据库连接2825
    4.2. 判断出来当前线程中已经存在事务
    4.3. 如果需要新开始事务,就先挂起数据库连接2825,挂起就是把test事务信息从事务同步管理器中转移到挂起资源对象中,并把当前a事务状态对象中的数据库连接设置为null
    4.4. a事务doBegin,新生成一个数据库连接2826,并设置到a事务状态对象中
    4.5. 把a事务信息设置到事务同步管理器中
    4.6. 执行a业务逻辑方法(可以利用事务同步管理器获取到a事务信息)
    4.7. 利用a事务状态对象,执行提交
    4.8. 提交之后会恢复所挂起的test事务,这里的恢复,其实只是把挂起资源对象中所保存的信息再转移回事务同步管理器中
  5. 继续执行test业务逻辑方法(仍然可以获取到test事务的信息)
  6. 利用test事务状态对象,执行提交

事务传播机制

事务定义的常用几个案例

情况1

开启两个默认的事务定义,进行调用 test 方法调用 a 方法实现两个方法的正常执行。

@Component
public class UserService {
    @Autowired
    private UserService userService;
    @Transactional
    public void test() {
        // test方法中的sql
        userService.a();
    }
    @Transactional
    public void a() {
        // a方法中的sql
    }
}

默认情况下传播机制为REQUIRED 所以上面这种情况的执行流程如下:

  1. 新建一个数据库连接conn
  2. 设置conn的autocommit为false
  3. 执行test方法中的sql
  4. 执行a方法中的sql
  5. 执行conn的commit()方法进行提交

情况2

开启两个默认的事务定义,进行调用在调用 test 的时候,先调用 a , 让 test 方法报错,实现两个方法事务的同时回滚。

@Component
public class UserService {
    @Autowired
    private UserService userService;
    @Transactional
    public void test() {
        // test方法中的sql
        userService.a();
        int result = 100/0;
    }
    @Transactional
    public void a() {
        // a方法中的sql
    }
}

所以上面这种情况的执行流程如下:

  1. 新建一个数据库连接conn
  2. 设置conn的autocommit为false
  3. 执行test方法中的sql
  4. 执行a方法中的sql
  5. 抛出异常
  6. 执行conn的rollback()方法进行回滚

情况3

开启两个默认的事务定义,进行调用在调用 test 的时候,先调用 a , 让 a 方法报错,实现两个方法事务的同时回滚。

@Component
public class UserService {
    @Autowired
    private UserService userService;
    @Transactional
    public void test() {
        // test方法中的sql
        userService.a();
    }
    @Transactional
    public void a() {
        // a方法中的sql
        int result = 100/0;
    }
}

所以上面这种情况的执行流程如下:

  1. 新建一个数据库连接conn
  2. 设置conn的autocommit为false
  3. 执行test方法中的sql
  4. 执行a方法中的sql
  5. 抛出异常
  6. 执行conn的rollback()方法进行回滚

情况4

开启两个默认的事务定义,进行调用在调用 test 的时候,先调用 a, a 是独立事务运行 , 让 a 方法报错,a 回滚,由于异常传播到 test 所以 test 也会回滚。

@Component
public class UserService {
    @Autowired
    private UserService userService;
    @Transactional
    public void test() {
        // test方法中的sql
        userService.a();
    }
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void a() {
        // a方法中的sql
        int result = 100/0;
    }
}

所以上面这种情况的执行流程如下:

  1. 新建一个数据库连接conn
  2. 设置conn的autocommit为false
  3. 执行test方法中的sql
  4. 又新建一个数据库连接conn2
  5. 执行a方法中的sql
  6. 抛出异常
  7. 执行conn2的rollback()方法进行回滚
  8. 继续抛异常
  9. 执行conn的rollback()方法进行回滚

开发中的常见问题

  1. 场景:通过 aop 进行代理动态设置数据源,在一个事务中调用不同库中的操作出现第二个库执行 SQL 的时候报错提示找不到表,并且设置数据源切换失败。 案例: 在项目中通过 aop 去动态设置数据源,当 a 操作(在d1库中执行)完成后去调用 b 操作(在 d2库中执行)如果用 @Transactional 标记开启事务那么,将返回数据源切换异常。 解决方案: 在将 b 操作的数据的事务传播机制进行修改为 REQUIRES_NEW 完整定义 @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = RuntimeException.class)。spring-tx 源码位置 TransactionAspectSupport#invokeWithinTransaction, createTransactionIfNecessary

Spring 源码解析