Spring事务Transaction实现原理

一、事务的总体设计

由于jdbcHibernate 实现事务功能的方式各不相同,Spring进行了统一的抽象,形成了PlatformTransactionManager事务管理器接口,事务的提交、回滚等操作全部交给它来实现。Spring的事务体系也是在PlatformTransactionManager事务管理器接口上开展开来的,所以先来了解下PlatformTransactionManager事务管理器。

先来看下三大接口

  • PlatformTransactionManager:事务管理器
  • TransactionDefinition:事务的一些基础信息,如超时时间、隔离级别、传播属性等
  • TransactionStatus:事务的一些状态信息,如是否是一个新的事务、是否已被标记为回滚

spring tx的入口就是在TxAdviceBeanDefinitionParser这里将解析tx的配置,生成TransactionInterceptor对象,这个也就是一个普通的切面类,只要符合AOP规则的调用都会进入此切面。transactionInterceptor支撑着整个事务功能的架构,逻辑还是相对复杂的,那么接下来分析此拦截器是如何实现事务特性的。

二、JDK动态代理

@Transactional的工作机制是基于AOP实现的,AOP又是使用动态代理实现的。

public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {

    @Override
    public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
        if (!config.isOptimize() && !config.isProxyTargetClass() 
                && !this.hasNoUserSuppliedProxyInterfaces(config)) {
            return new JdkDynamicAopProxy(config);
        } else {
            Class<?> targetClass = config.getTargetClass();
            if (targetClass == null) {
                throw new AopConfigException("TargetSource cannot determine target class:" +
                        " Either an interface or a target is required for proxy creation.");
            } else {
                return (AopProxy)(!targetClass.isInterface() && !Proxy.isProxyClass(targetClass) 
                            ? new ObjenesisCglibAopProxy(config)
                            : new JdkDynamicAopProxy(config));
            }
        }
    }
    
    // ...
}

如果目标对象实现了接口,默认情况下会采用JDK的动态代理,如果目标对象没有实现了接口,会使用 CGLIB动态代理。

所以,使用JDK动态代理执行目标方法(比如:userService.save),实际上是执行的JdkDynamicAopProxy#invoke()方法。

// org.springframework.aop.framework.JdkDynamicAopProxy.invoke
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    Object oldProxy = null;
    boolean setProxyContext = false;
 
    // 1. 获取到目标对象,也就是被代理对象的引用
    TargetSource targetSource = this.advised.targetSource;
    Object target = null;
 
    try {
        // 如果目标对象未实现equals()方法,则不需要代理
        if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
            // The target does not implement the equals(Object) method itself.
            return equals(args[0]);
        }
        // 如果目标对象未实现hashCode()方法,则不需要代理
        else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
            // The target does not implement the hashCode() method itself.
            return hashCode();
        }
        // 如果方法是DecoratingProxy类型,也不需要拦截器执行
        else if (method.getDeclaringClass() == DecoratingProxy.class) {
            // There is only getDecoratedClass() declared -> dispatch to proxy config.
            return AopProxyUtils.ultimateTargetClass(this.advised);
        }
        // 如果是Advised接口或者其父接口中定义的方法,则直接反射调用,不应用通知
        else if (!this.advised.opaque && method.getDeclaringClass().isInterface()
                 && method.getDeclaringClass().isAssignableFrom(Advised.class)) {
            // Service invocations on ProxyConfig with the proxy config...
            return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
        }
 
        Object retVal;
 
        // 2. 如果exposeProxy属性值为true,则将代理对象暴露到ThreadLocal中
        // exposeProxy是通过注解@EnableAspectJAutoProxy(exposeProxy = true)进行指定的,如果配置为true,
        // 则可以使用AopContext.currentProxy()获取到代理对象。在Spring事务方法自调用的时候经常使用到。
        if (this.advised.exposeProxy) {
            // 将代理对象暴露到ThreadLocal中
            oldProxy = AopContext.setCurrentProxy(proxy);
            setProxyContext = true;
        }
 
        // 3. 获得目标对象实例
        target = targetSource.getTarget();
 
        // 获取目标对象的类型
        Class<?> targetClass = (target != null ? target.getClass() : null);
 
        // 4. 获得目标方法对应的拦截器链
        List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method,
                    targetClass);
 
        // 5. 如果对应的拦截器链为空,也就是没有可以应用到此方法的通知(Interceptor),
        //  则直接通过反射方式进行调用 ==> method.invoke(target, args)
        if (chain.isEmpty()) {
            // We can skip creating a MethodInvocation: just invoke the target directly
            // Note that the final invoker must be an InvokerInterceptor so we know it does
            // nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
            Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
            retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
        } else {
            // 6. 如果拦截器链不为空,则需要创建一个MethodInvocation(方法调用对象)
            MethodInvocation invocation =
                new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
            // 调用其proceed方法,实际上是调用ReflectiveMethodInvocation.proceed()方法
            retVal = invocation.proceed();
        }
 
        // 7. 必要时转换返回值
        Class<?> returnType = method.getReturnType();
        if (retVal != null && retVal == target
            && returnType != Object.class && returnType.isInstance(proxy)
            && !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
            // Special case: it returned "this" and the return type of the method
            // is type-compatible. Note that we can't help if the target sets
            // a reference to itself in another returned object.
            retVal = proxy;
        }
        else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
            throw new AopInvocationException(
                "Null return value from advice does not match primitive return type for: " + method);
        }
        return retVal;
    } finally {
        if (target != null && !targetSource.isStatic()) {
            // Must have come from TargetSource.
            targetSource.releaseTarget(target);
        }
 
        if (setProxyContext) {
            // Restore old proxy.
 
            // 恢复ThreadLocal中的旧代理对象
            AopContext.setCurrentProxy(oldProxy);
        }
    }
}

invoke()方法的处理流程大体如下:

  1. 获取到目标对象,也就是被代理对象的引用;
  2. 处理exposeProxy属性,如果exposeProxy属性值为true,则将代理对象暴露到ThreadLocal中;
  3. 获得目标方法对应的拦截器链;
  4. 如果对应的拦截器链为空,也就是没有可以应用到此方法的通知(Interceptor),则直接通过反射方式进行调用;
  5. 如果拦截器链不为空,则需要创建一个MethodInvocation(方法调用对象),调用其proceed方法,实际上是调用ReflectiveMethodInvocation.proceed()方法;
  6. 有需要的话,转换返回值;

invoke()方法内部有三个比较重要的方法:

  • getInterceptorsAndDynamicInterceptionAdvice():获得目标方法对应的拦截器链
  • invokeJoinpointUsingReflection():通过反射方式调用目标方法
  • MethodInvocation#proceed():执行拦截器链方法

接下来我们进入invocation.proceed()方法,实际上是调用ReflectiveMethodInvocation.proceed()方法。

public Object proceed() throws Throwable {
    // We start with an index of -1 and increment early.
 
    // 1. 当前拦截器下标:
    // 从-1的位置开始,直到满足 索引下标 =(拦截器的长度  -1)的条件(所有拦截器都执行完毕),此时需要执行目标方法
    if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
        // 执行目标方法
        return invokeJoinpoint();
    }
 
    // 2. 每次调用时,将索引的值递增,从拦截器链中获取下一个需要执行的拦截器
    Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers
            .get(++this.currentInterceptorIndex);
 
    // 动态方法匹配拦截器
    if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
        // Evaluate dynamic method matcher here: static part will already have
        // been evaluated and found to match.
        InterceptorAndDynamicMethodMatcher dm =
            (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
        // 目标类所属类型
        Class<?> targetClass = (this.targetClass != null 
                ? this.targetClass 
                : this.method.getDeclaringClass());
 
        // 动态匹配,判断运行时参数是否匹配
        if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
            // 如果匹配成功,则执行当前拦截器逻辑
            return dm.interceptor.invoke(this);
        } else {
            // 如果匹配失败,则会跳过当前拦截器interceptor,则会调用proceed()方法执行拦截器链中的下一个拦截器的处理
            return proceed();
        }
 
    } else {
        // It's an interceptor, so we just invoke it: The pointcut will have
        // been evaluated statically before this object was constructed.
 
        // 3. 只是一个普通的拦截器,则触发拦截器链责任链的调用,并且参数为ReflectiveMethodInvocation本身
        return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
    }
}

首先获取到拦截器链中的第一个拦截器,也就是前面的TransactionInterceptor,然后执行TransactionInterceptor#invoke方法。

spring在处理事务的aop增强时,主要调用了return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);

三、事务的拦截器 - TransactionInterceptor

TranctionInterceptor位于spring-tx-*.jarorg.springframework.transaction.interceptor包中,结构如下:

  • 继承TransactionAspectSupport类:其实对其进行了增强(模板方法模式)。
  • 实现MethodInterceptor接口:方法拦截器,执行代理类的目标方法,会触发invoke方法执行。
public class TransactionInterceptor
        extends TransactionAspectSupport
        implements MethodInterceptor, Serializable {

   //...

   // 实现了MethodInterceptor接口的invoke方法
   @Nullable
   public Object invoke(MethodInvocation invocation) throws Throwable {
       
      // 获取目标类
      Class<?> targetClass = invocation.getThis() != null
              ? AopUtils.getTargetClass(invocation.getThis())
              : null;
      
      // 父类TransactionAspectSupport的模板方法
      return this.invokeWithinTransaction(invocation.getMethod(), targetClass,
              invocation::proceed);
   }
}

通过调用父类TransactionAspectSupportinvokeWithinTransaction方法进行事务处理,以事务的方式调用目标方法。

3.1 invokeWithinTransaction方法

抽象类TransactionAspectSupport(基类)的invokeWithinTransaction方法(重点)。

public abstract class TransactionAspectSupport implements BeanFactoryAware, InitializingBean {

    // protected修饰,不允许其他包和无关类调用
    protected Object invokeWithinTransaction(Method method, Class<?> targetClass, 
                                             final InvocationCallback invocation) 
            throws Throwable {

        // 获取事务属性源
        TransactionAttributeSource tas = this.getTransactionAttributeSource();

        // 获取事务对应的属性 如果事务属性为空(则目标方法不存在事务)
        TransactionAttribute txAttr = tas != null 
                ? tas.getTransactionAttribute(method, targetClass) 
                : null;

        // 获取事务管理器

        // 根据事务的属性获取beanFactory中的PlatformTransactionManager(spring事务管理器的顶级接口),
        // 一般获得的是DataSourceTransactionManager
        TransactionManager tm = this.determineTransactionManager(txAttr);

        // 目标方法唯一标识(类.方法,如service.UserServiceImpl.save)
        final String joinpointIdentification = methodIdentification(method, targetClass);

        // 如果txAttr为空或者tm 属于非CallbackPreferringPlatformTransactionManager,执行目标增强  ①
        if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {

            //看是否有必要创建一个事务,根据事务传播行为,做出相应的判断
            TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
            Object retVal = null;
            try {
                //回调方法执行,执行目标方法(原有的业务逻辑)
                retVal = invocation.proceedWithInvocation();
            } catch (Throwable ex) {
                // 异常回滚
                completeTransactionAfterThrowing(txInfo, ex);
                throw ex;
            } finally {
                //清除信息
                cleanupTransactionInfo(txInfo);
            }
            //提交事务
            commitTransactionAfterReturning(txInfo);
            return retVal;
        } else {
            //...
            //编程式事务处理(CallbackPreferringPlatformTransactionManager) 不做重点分析
        }
   }
   //...
}

TransactionAspectSupport#invokeWithinTransaction()方法的处理流程:

  1. 获取事务属性源;
  2. 获取事务对应的属性;
  3. 获取PlatformTransactionManager事务管理器;
  4. 组装方法的唯一标识,例如com.test.service.UserServiceImpl.save
  5. 针对声明式事务、编程式事务的处理,在项目中我们通常都是使用声明式事务的方式,所以这里以声明式事务为例进行介绍;
  6. 通过createTransactionIfNecessary()方法创建一个事务;
  7. invocation.proceedWithInvocation()执行增强方法(环绕通知);
  8. 如果事务方法执行未发生异常,则调用commitTransactionAfterReturning(txInfo)进行提交事务;
  9. 如果事务方法执行发生异常,则调用completeTransactionAfterThrowing(txInfo, ex)进行异常回滚;

3.2 createTransactionIfNecessary方法

重点分析createTransactionIfNecessary方法,会判断是否存在事务,根据事务的传播属性,做出不同的处理,也是做了一层包装,核心是通过TransactionStatus来判断事务的属性。通过持有的PlatformTransactionManager来获取TransactionStatus

protected TransactionInfo createTransactionIfNecessary(
        @Nullable PlatformTransactionManager tm,
        @Nullable TransactionAttribute txAttr,
        final String joinpointIdentification) {
        
    // 如果没有名称指定则使用方法唯一标识,并使用DelegatingTransactionAttribute封装txAttr
    if (txAttr != null && ((TransactionAttribute)txAttr).getName() == null) {
        txAttr = new DelegatingTransactionAttribute((TransactionAttribute)txAttr) {
            public String getName() {
                return joinpointIdentification;
            }
        };
    }

    TransactionStatus status = null;
    if (txAttr != null) {
        if (tm != null) {
            // 获取TransactionStatus事务状态信息
            status = tm.getTransaction((TransactionDefinition)txAttr);
        } else if (this.logger.isDebugEnabled()) {
            this.logger.debug("Skipping transactional joinpoint [" + joinpointIdentification
                    + "] because no transaction manager has been configured");
        }
    }
    // 根据指定的属性与status准备一个TransactionInfo
    return this.prepareTransactionInfo(tm, (TransactionAttribute)txAttr,
            joinpointIdentification, status);
}

createTransactionIfNecessary()创建事务主要分为两个步骤:

  1. getTransaction方法返回当前活动事务或创建一个新的事务。这个底下会讲。
  2. prepareTransactionInfo方法准备TransactionInfo
protected TransactionInfo prepareTransactionInfo(PlatformTransactionManager tm,
        TransactionAttribute txAttr, String joinpointIdentification, 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.
    txInfo.bindToThread();
    return txInfo;
}

prepareTransactionInfo方法把事务状态和事务属性等信息封装成一个TransactionInfo对象,并绑定到当前线程的ThreadLocal

private void bindToThread() {
    // Expose current TransactionStatus, preserving any existing TransactionStatus
    // for restoration after this transaction is complete.
    this.oldTransactionInfo = transactionInfoHolder.get();
    transactionInfoHolder.set(this);
}

3.3 proceedWithInvocation方法

然后再返回到上层代码,接着就是执行相应的逻辑代码了。

retVal = invocation.proceedWithInvocation();

proceedWithInvocation其实是一个钩子函数,执行proceedWithInvocation方法时,会回来ReflectiveMethodInvocation#proceed()方法中,前面已经介绍到,从拦截器链中获取到了第一个拦截器进行执行,从前面可以看到,拦截器链中就只有一个拦截器。所以满足下面这个条件:

public Object proceed() throws Throwable {
    if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
        //执行目标方法
        return this.invokeJoinpoint();
    } else {
        Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers
              .get(++this.currentInterceptorIndex);
        if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
            InterceptorAndDynamicMethodMatcher dm = 
                  (InterceptorAndDynamicMethodMatcher)interceptorOrInterceptionAdvice;
            Class<?> targetClass = this.targetClass != null 
                 ? this.targetClass 
                 : this.method.getDeclaringClass();
            return dm.methodMatcher.matches(this.method, targetClass, this.arguments) 
                 ? dm.interceptor.invoke(this) 
                 : this.proceed();
        } else {
            return ((MethodInterceptor)interceptorOrInterceptionAdvice).invoke(this);
        }
    }
}

将会执行invokeJoinpoint()目标方法,其实就是执行我们的代理类的方法(如:save方法)。

3.4 cleanupTransactionInfo方法

执行过程的finally代码块将执行cleanupTransactionInfo(txInfo);

protected void cleanupTransactionInfo(TransactionInfo txInfo) {
    if (txInfo != null) {
        //这里就是将txInfo进行重置工作,让它恢复到前一个状态。
        txInfo.restoreThreadLocalStatus();
    }
}

3.5 commitTransactionAfterReturning方法

然后就是提交操作(commitTransactionAfterReturning)或者是回滚操作(completeTransactionAfterThrowing)了。这里就拿提交操作来为例来说明,回滚操作类似:

protected void commitTransactionAfterReturning(TransactionInfo txInfo) {
    if (txInfo != null && txInfo.hasTransaction()) {
        if (logger.isTraceEnabled()) {
            logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() + "]");
        }
        txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
    }
}

commit方法就是提交事务。

四、事务的定义 - TransactionDefinition

事务属性通过TransactionDefinition接口实现定义,主要有事务隔离级别、事务传播行为、事务超时时间、事务是否只读。

public interface TransactionDefinition {

    //事务传播行为类型:如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。
    int PROPAGATION_REQUIRED = 0;
    //事务传播行为类型:支持当前事务,如果当前没有事务,就以非事务方式执行。 
    int PROPAGATION_SUPPORTS = 1;
    //事务传播行为类型:当前如果有事务,Spring就会使用该事务;否则会抛出异常
    int PROPAGATION_MANDATORY = 2;
    //事务传播行为类型:新建事务,如果当前存在事务,把当前事务挂起。 
    int PROPAGATION_REQUIRES_NEW = 3;
    //事务传播行为类型:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 
    int PROPAGATION_NOT_SUPPORTED = 4;
    //事务传播行为类型:即使当前有事务,Spring也会在非事务环境下执行。如果当前有事务,则抛出异常
    int PROPAGATION_NEVER = 5;
    //事务传播行为类型:如果当前存在事务,则在嵌套事务内执行。
    int PROPAGATION_NESTED = 6;

    //隔离级别:默认的隔离级别(对mysql数据库来说就是ISOLATION_ READ_COMMITTED,可以重复读)
    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;

    //默认事务的超时时间
    int TIMEOUT_DEFAULT = -1;

    //获取事务的传播行为
    int getPropagationBehavior();
    //获取事务的隔离级别
    int getIsolationLevel();
    //获取超时时间
    int getTimeout();

    //是否只读
    boolean isReadOnly();
    //事务名称
    String getName();
}

TransactionAttributeTransactionDefinition的实现接口

public interface TransactionAttribute extends TransactionDefinition {

    //事务的目标方法的完整限定方法名称
    String getQualifier();

    //对于给定的异常信息,是否回滚
    boolean rollbackOn(Throwable ex);
}

获取TransactionAttribute

在执行目标方法之前,获取事务之前,执行的目标增强。spring是从事务来源中获取事务的属性TransactionAttribute

  • spring基于注解事务和声明事务的事务来源为:AnnotationTransactionAttributeSourceNameMatchTransactionAttributeSource
  • spring基于注解事务和声明事务的TransactionDefinition默认实现都为是RuleBasedTransactionAttribute
protected Object invokeWithinTransaction(Method method, Class<?> targetClass, 
                                        final InvocationCallback invocation) throws Throwable {
    final TransactionAttribute txAttr = getTransactionAttributeSource()
                       .getTransactionAttribute(method, targetClass);
}

4.1 事务传播行为

传播行为定义了被调用方法的事务边界。

传播行为 意义
propagation_required 当前方法必须运行在一个事务中,如果当前存在一个事务,那么该方法运行在这个事务中,
否则,将创建一个新的事务
propagation_supports 当前方法不需要运行在一个是事务中,但如果有一个事务已经存在,该方法也可以运行在这个事务中
propagation_mandatory 方法必须运行在一个事务中,如果当前事务不存在,就抛出异常
propagation_requires_new 当前方法必须运行在自己的事务中,如果当前存在一个事务,那么这个事务将在该方法运行期间被挂起
propagation_not_supported 方法不能运行在一个事务中,如果当前存在一个事务,则该方法将被挂起
propagation_never 方法不能运行在一个事务中,否则抛出异常
propagation_nested 如果当前事务存在,则方法应该运行在一个嵌套事务中。否则和propagation_required一样

4.2 隔离级别

在操作数据时可能带来3个副作用,分别是脏读、不可重复读、幻读。为了避免这3中副作用的发生,在标准的SQL语句中定义了4种隔离级别,分别是未提交读、已提交读、可重复读、可序列化

而在spring事务中提供了5种隔离级别来对应在SQL中定义的4种隔离级别,如下:

隔离级别 意义
isolation_default 使用后端数据库默认的隔离级别
isolation_read_uncommitted 允许读取未提交的数据(对应未提交读),可能导致脏读、不可重复读、幻读
isolation_read_committed 允许在一个事务中读取另一个已经提交的事务中的数据(对应已提交读)。
可以避免脏读,但是无法避免不可重复读和幻读
isolation_repeatable_read 一个事务不可能更新由另一个事务修改但尚未提交(回滚)的数据(对应可重复读)。
可以避免脏读和不可重复读,但无法避免幻读
isolation_serializable 这种隔离级别是所有的事务都在一个执行队列中,依次顺序执行,而不是并行(对应可序列化)。
可以避免脏读、不可重复读、幻读。但是这种隔离级别效率很低,不建议使用。

4.3 只读

将事务标识为只读,只读事务不修改任何数据。

如果在一个事务中所有关于数据库的操作都是只读的,也就是说,这些操作只读取数据库中的数据,而并不更新数据,那么应将事务设为只读模式(read_only_marker),这样更有利于数据库进行优化。

因为只读的优化措施是事务启动后由数据库实施的,因此,只有将那些具有可能启动新事务的传播行为(propagation_nestedpropagation_requiredpropagation_required_new)的方法的事务标记成只读才有意义。

对于错误的事务只读设置将抛出IllegalTransactionStateException异常,并伴随“Participating transaction with definition [……] is not marked as read-only……”信息,表示参与的事务只读属性设置错误。

4.4 事务超时

如果一个事务长时间运行,这时为了尽量避免浪费系统资源,应为这个事务设置一个有效时间,使其等待数秒后自动回滚。与设置“只读”属性一样,事务有效属性也需要给那些具有可能启动新事物的传播行为的方法的事务标记成只读才有意义。

五、事务的管理器 - PlatformTransactionManager

由于实现事务功能的方式各不相同,Spring进行了统一的抽象,形成了PlatformTransactionManager事务管理器顶级接口(平台事务管理器),事务的提交、回滚等操作全部交给它来实现

public interface PlatformTransactionManager {

    //获取一个具体的事务状态信息
    TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;

    //提交一个事务状态信息
    void commit(TransactionStatus status) throws TransactionException;

    //回滚一个事务状态信息
    void rollback(TransactionStatus status) throws TransactionException;
}

PlatformTransactionManager是一个接口,AbstractPlatformTransactionManager实现该接口,getTransaction方法也是该类实现的。

spring中存在很多模板方法,对于Abstract开头的封装的抽象类,基本都有模板方法,且为final修饰。

  1. DataSourceTransactionManager(事务管理器接口定义PlatformTransactionManager)
  2. PlatformTransactionManager
    • AbstractPlatformTransactionManager
      • DataSourceTransactionManager(重点)
      • HibernateTransactionManager
      • JpaTransactionManager

一般我们给事务管理器的默认实现为DataSourceTransactionManager

<!-- 事务管理器配置 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource" />
</bean>

5.1 获取事务

大体内容就是先获取上述说明(TransactionStatus)的事务对象,判断当前事务是否已存在,如果存在则进行事务的传播属性处理,后面详细说明,如果不存在new DefaultTransactionStatus,新创建一个事务,同时使用事务对象开启事务。

不同的事务管理器获取不同的事务对象

  1. 获取事务对象:
  2. 构建DefaultTransactionStatus,使用事务对象
@Override
public final TransactionStatus getTransaction(TransactionDefinition definition) 
        throws TransactionException {
    
    // 调用PlatformTransactionManager的getTransaction方法,获取TransactionStatus开启一个事务
    Object transaction = doGetTransaction();
    
    // Cache debug flag to avoid repeated checks.
    boolean debugEnabled = logger.isDebugEnabled();
    
    if (definition == null) {
        // Use defaults if no transaction definition given.
        definition = new DefaultTransactionDefinition();
    }
    
    // 这个判断很重要,是否已经存在的一个transaction
    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.
    // 当前线程不存在事务,并且PropagationBehavior(传播行为)是PROPAGATION_MANDATORY的话,会抛出异常
    if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
        throw new IllegalTransactionStateException(
                "No existing transaction found for transaction marked with propagation 'mandatory'");
    }
    
    //如果是PROPAGATION_REQUIRED,PROPAGATION_REQUIRES_NEW,PROPAGATION_NESTED这三种类型将开启一个新的事务
    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);
                    
            // 开启新事务
            doBegin(transaction, definition);
            
            // 准备Synchronization
            prepareSynchronization(status, definition);
            return status;
        } catch (RuntimeException ex) {
            resume(null, suspendedResources);
            throw ex;
        } catch (Error err) {
            resume(null, suspendedResources);
            throw err;
        }
    } 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);
    }
}

这段代码比较长也是比较核心的一段代码,让我们来慢慢分析,首先这里将执行doGetTransaction方法来获取一个transaction,和dobegin方法如何开启一个事务。

AbstractPlatformTransactionManager并没有给出doGetTransaction的具体实现,而是由子类实现。这里以分析实现类DataSourceTransactionManager的具体方法。

public class DataSourceTransactionManager extends AbstractPlatformTransactionManager
        implements ResourceTransactionManager, InitializingBean {
    private DataSource dataSource;

    @Override
    protected Object doGetTransaction() {
        DataSourceTransactionObject txObject = new DataSourceTransactionObject();
        txObject.setSavepointAllowed(isNestedTransactionAllowed());
        //这一行代码中TransactionSynchronizationManager很重要,是对connection的核心获取、持有、删除等
        ConnectionHolder conHolder =
                (ConnectionHolder) TransactionSynchronizationManager.getResource(this.dataSource);
        //这里不论获取到或者获取不到都将此设置newConnectionHolder为false
        txObject.setConnectionHolder(conHolder, false);
        return txObject;
    }
}

这段代码中主要是根据this.dataSource来获取ConnectionHolder,这个ConnectionHolder是放在TransactionSynchronizationManagerThreadLocal中持有的,如果是第一次来获取,肯定得到是null

接着代码往下将执行到isExistingTransaction(transaction),这里主要是依据下面代码判断:

@Override
protected boolean isExistingTransaction(Object transaction) {
    DataSourceTransactionObject txObject = (DataSourceTransactionObject)transaction;
    //如果是第一次开启事务这里必然是false,否则将返回true。        
    return txObject.hasConnectionHolder() 
         && txObject.getConnectionHolder().isTransactionActive();        
}

我们这里先讨论第一次进入的情况,也就是false的时候将继续往下执行到了判断事务Propagation的时候了,如果Propagation为:PROPAGATION_REQUIREDPROPAGATION_REQUIRES_NEWPROPAGATION_NESTED中的一个将开启一个新事物,new一个新的DefaultTransactionStatus,并且newTransaction设置为true,这个状态很重要,因为后面的不论回滚、提交都是根据这个属性来判断是否在这个TransactionStatus上来进行。

接着根据我们配置的不同的传播行为进行处理。由于这里我们没有指定传播行为,所以使用默认的PROPAGATION_REQUIRED,所以会执行suspend方法。

 @Nullable
protected final SuspendedResourcesHolder suspend(@Nullable Object transaction) 
      throws TransactionException {
    // 判断当前线程中是否存在已经激活的事务
    if (TransactionSynchronizationManager.isSynchronizationActive()) {
        List suspendedSynchronizations = this.doSuspendSynchronization();

        try {
            Object suspendedResources = null;
            if (transaction != null) {
               suspendedResources = this.doSuspend(transaction);
            }
            // 当前已经存在的事务名称
            String name = TransactionSynchronizationManager.getCurrentTransactionName();
            
            // 将ThreadLocal<String> currentTransactionName的值置空
            TransactionSynchronizationManager.setCurrentTransactionName((String)null);
            
            // 是否是只读事务
            boolean readOnly = TransactionSynchronizationManager.isCurrentTransactionReadOnly();
            
            // 将ThreadLocal<Boolean> currentTransactionReadOnly的值置空
            TransactionSynchronizationManager.setCurrentTransactionReadOnly(false);
            
            // 事务隔离级别
            Integer isolationLevel = TransactionSynchronizationManager
                        .getCurrentTransactionIsolationLevel();
            
            // 将ThreadLocal<Integer> currentTransactionIsolationLevel的值置空
            TransactionSynchronizationManager.setCurrentTransactionIsolationLevel((Integer)null);
            
            // 事务是否激活状态
            boolean wasActive = TransactionSynchronizationManager.isActualTransactionActive();
            
            // 将ThreadLocal<Boolean> actualTransactionActive的值置空
            TransactionSynchronizationManager.setActualTransactionActive(false);
            
            // 把前面从线程变量中获取出来的存在事务属性封装为挂起的事务属性返回出去
            return new SuspendedResourcesHolder(suspendedResources, suspendedSynchronizations,
                  name, readOnly, isolationLevel, wasActive);
         } catch (Error | RuntimeException ex) {
            this.doResumeSynchronization(suspendedSynchronizations);
            throw ex;
         }
   } else if (transaction != null) {
         Object suspendedResources = this.doSuspend(transaction);
         return new SuspendedResourcesHolder(suspendedResources);
   } else {
      return null;
   }
}

suspend(null)方法执行完成后,通过newTransactionStatus()创建一个DefaultTransactionStatus对象。

protected DefaultTransactionStatus newTransactionStatus(
    TransactionDefinition definition, @Nullable Object transaction, boolean newTransaction,
    boolean newSynchronization, boolean debug, @Nullable Object suspendedResources) {
 
    boolean actualNewSynchronization = newSynchronization &&
        !TransactionSynchronizationManager.isSynchronizationActive();
    return new DefaultTransactionStatus(
        transaction, newTransaction, actualNewSynchronization,
        definition.isReadOnly(), debug, suspendedResources);
}

接着将执行doBegin方法

5.2 开启事务

DataSourceTransactionManagerDataSourceTransactionObject开启过程如下:

首先判断之前的获取当前线程绑定的ConnectionHolder是否为null,如果为null,从dataSource中获取一个Connection,封装成ConnectionHolder,然后再绑定到当前线程。

因为开启了一个事务,则必须要关闭DataSourceTransactionObjectConnection的自动提交,代码如下:

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

    try {
        //如果ConnectionHolder是否为null,从新获取
        if (txObject.getConnectionHolder() == null ||
                txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
            //从dataSource中获取一个Connection    
            Connection newCon = this.dataSource.getConnection();
            if (logger.isDebugEnabled()) {
                logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
            }
            //为当前Transaction设置ConnectionHolder,并且设置newConnectionHolder为true
            txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
        }

        txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
        con = txObject.getConnectionHolder().getConnection();

        //这里主要是根据definition对connection进行一些设置
        Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con,
               definition);
        txObject.setPreviousIsolationLevel(previousIsolationLevel);

        // 取消自动提交
        if (con.getAutoCommit()) {
            txObject.setMustRestoreAutoCommit(true);
            if (logger.isDebugEnabled()) {
                logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
            }
            //开启事务,设置autoCommit为false
            con.setAutoCommit(false);
        }
        //这里设置transactionActive为true,还记得签名判断是否存在的transaction吧?就是根据这个
        txObject.getConnectionHolder().setTransactionActive(true);

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

        //如果是新增的ConnectionHolder,则绑定到当前线程
        if (txObject.isNewConnectionHolder()) {
            //将当前的connection放入TransactionSynchronizationManager中持有,下次调用可以判断为已有的事务
            TransactionSynchronizationManager.bindResource(getDataSource(),
                txObject.getConnectionHolder());
        }
    } catch (Throwable ex) {
        if (txObject.isNewConnectionHolder()) {
            DataSourceUtils.releaseConnection(con, this.dataSource);
            txObject.setConnectionHolder(null, false);
        }
        throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction",
            ex);
    }
}

TransactionSynchronizationManager中持有,记得前面doGetTransaction方法吧,如果同一个线程,再此进入执行的话就会获取到同一个ConnectionHolder,在后面的isExistingTransaction方法也可以判定为是已有的transaction

接下来将执行prepareSynchronization方法,主要是对TransactionSynchronizationManager的一系列设置。

protected void prepareSynchronization(DefaultTransactionStatus status,
      TransactionDefinition definition) {
    if (status.isNewSynchronization()) {
        // 事务激活标识:设置ThreadLocal<Boolean> actualTransactionActive的值
        TransactionSynchronizationManager.setActualTransactionActive(status.hasTransaction());
        
        // 事务隔离级别:设置ThreadLocal<Integer> currentTransactionIsolationLevel的值
        TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(
            definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT 
                ? definition.getIsolationLevel() 
                : null);
        // 是否只读事务:设置ThreadLocal<Boolean> currentTransactionReadOnly的值
        TransactionSynchronizationManager.setCurrentTransactionReadOnly(definition.isReadOnly());
        
        // 事务名称:设置ThreadLocal<String> currentTransactionName的值
        TransactionSynchronizationManager.setCurrentTransactionName(definition.getName());
        // 初始化Synchronization
        TransactionSynchronizationManager.initSynchronization();
    }
}

5.3 回滚事务

回滚,则还是利用DefaultTransactionStatus内部的Object transaction来执行回滚操作。

DataSourceTransactionManager就是使用DataSourceTransactionObject中的Connection来进行回滚操作。

@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);
    }
}

5.4 提交事务

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");
    } else {
        DefaultTransactionStatus defStatus = (DefaultTransactionStatus)status;
        if (defStatus.isLocalRollbackOnly()) {
            if (defStatus.isDebug()) {
                this.logger.debug("Transactional code has requested rollback");
            }

            this.processRollback(defStatus, false);
        } else if (!this.shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) {
            if (defStatus.isDebug()) {
                this.logger.debug("Global transaction is marked as rollback-only but transactional"
                   + " code requested commit");
            }

            this.processRollback(defStatus, true);
        } else {
            this.processCommit(defStatus);
        }
    }
}

实际就是执行的processCommit方法。

private void processCommit(DefaultTransactionStatus status) throws TransactionException {
    try {
        boolean beforeCompletionInvoked = false;
        try {
            prepareForCommit(status);
            triggerBeforeCommit(status);
            triggerBeforeCompletion(status);
            beforeCompletionInvoked = true;
            boolean globalRollbackOnly = false;
            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.
            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
            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);
    }
}

首先将执行一些提交前的准备工作,这里将进行是否有savepoint判断status.hasSavepoint(),如果有的话将进行释放savePoint,即getConnectionHolderForSavepoint().getConnection().releaseSavepoint((Savepoint) savepoint);接着就判断是否是新的transaction:status.isNewTransaction(),如果是的话将执行doCommit(status);

@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 {
        //其实也就是调用了Connection的commit()方法。
        con.commit();
    } catch (SQLException ex) {
        throw new TransactionSystemException("Could not commit JDBC transaction", ex);
    }
}

最后无论成功与否都将调用finally块中的cleanupAfterCompletion(status)

private void cleanupAfterCompletion(DefaultTransactionStatus status) {
    status.setCompleted();
    if (status.isNewSynchronization()) {
        //TransactionSynchronizationManager清理工作
        TransactionSynchronizationManager.clear();
    }
    if (status.isNewTransaction()) {
        //这个比较重要(重点分析)
        doCleanupAfterCompletion(status.getTransaction());
    }
    if (status.getSuspendedResources() != null) {
        if (status.isDebug()) {
            logger.debug("Resuming suspended transaction after completion of inner transaction");
        }
        resume(status.getTransaction(), (SuspendedResourcesHolder) status.getSuspendedResources());
    }
}

首先对TransactionSynchronizationManager进行一系列清理工作,然后就将执行doCleanupAfterCompletion方法:

@Override
protected void doCleanupAfterCompletion(Object transaction) {
    DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;

    // Remove the connection holder from the thread, if exposed.
    if (txObject.isNewConnectionHolder()) {
        //从TransactionSynchronizationManager中解绑相应的connectionHolder
        TransactionSynchronizationManager.unbindResource(this.dataSource);
    }

    // Reset connection.
    Connection con = txObject.getConnectionHolder().getConnection();
    try {
        if (txObject.isMustRestoreAutoCommit()) {
            //对获取到的Connection进行一些还原
            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");
        }
        //如果是newConnection将这个链接关闭,如果是连接池将还给连接池
        DataSourceUtils.releaseConnection(con, this.dataSource);
    }
    //这里将这只transactionActive为false
    txObject.getConnectionHolder().clear();
}

其实就是将TransactionSynchronizationManager中持有的connectionHolder释放,并且还原当前Connection的状态,然后将对当前的transaction进行清理包括设置transactionActivefalse等。

六、事务的状态 - TransactionStatus

TransactionStatus表示一个具体的事务状态(这里应用到了Java的一个多继承,接口允许多继承)

TransactionStatus它继承了SavepointManager接口,SavepointManager是对事务中上述保存点功能的封装(Spring利用保存点功能实现了事务的嵌套功能。后面会详细说明)

public interface SavepointManager {

    Object createSavepoint() throws TransactionException;

    void rollbackToSavepoint(Object savepoint) throws TransactionException;

    void releaseSavepoint(Object savepoint) throws TransactionException;
}

public interface TransactionStatus extends SavepointManager, Flushable {

    //是否是一个新的事物
    boolean isNewTransaction();

    //是否有保存点
    boolean hasSavepoint();

    void setRollbackOnly();

    //是否已被标记为回滚
    boolean isRollbackOnly();

    @Override
    void flush();

    boolean isCompleted();
}

6.1 DefaultTransactionStatus

常用的TransactionStatus接口实现为DefaultTransactionStatus

public class DefaultTransactionStatus extends AbstractTransactionStatus {

    private final Object transaction;

    private final boolean newTransaction;

    private final boolean newSynchronization;

    private final boolean readOnly;

    private final boolean debug;

    private final Object suspendedResources;
    
    //...
}

目前jdbc事务是通过Connection来实现事务的,Hibernate是通过它自己定义的Transaction来实现的,所以各家的事务都不同,所以Spring只能以Object transaction的形式来表示各家的事务,事务的回滚和提交等操作都会最终委托给上述Object transaction来完成。

Object transaction的职责就是提交回滚事务,这个transaction的选择可能如下:

  • DataSourceTransactionObject
  • HibernateTransactionObject
  • JpaTransactionObject

详细信息分别如下:

  • DataSourceTransactionObject:我们使用了dataSource来获取连接,要想实现事务功能,必然需要使用Connection,所以它中肯定有一个Connection来执行事务的操作。DataSourceTransactionObject中有一个ConnectionHolder,它封装了一个Connection。
  • HibernateTransactionObject:我们使用了hibernate,此时要想实现事务功能,必然需要通过hibernate自己定义的Transaction来实现。HibernateTransactionObject中含有一个SessionHolder,和上面的ConnectionHolder一样,它封装了一个Session,有了Session,我们就可以通过Session来产生一个Hibernate的Transaction,从而实现事务操作。

6.1.1 DefaultTransactionStatus的获取

DefaultTransactionStatus的获取是事务管理器的方法,这里的实现是AbstractPlatformTransactionManager提供的模板方法。

在获取Object transaction之后,先进行判断,是否是已存在的事务。因为这个Object transaction的获取过程就是直接从线程绑定的获取的,可能当前线程已经存在事务。

@Override
public final TransactionStatus getTransaction(TransactionDefinition definition) 
        throws TransactionException {
    
    //获取相应的Object transaction
    Object transaction = doGetTransaction();
    
    //就是依据和当前线程绑定的ConnectionHolder中是否已存在事务(也是依据和当前线程绑定的SessionHolder是否已存在事务)
    if (isExistingTransaction(transaction)) {
        //如果是已存在事务:则需要对事务的传播属性进行处理,如下即上述截图中的的handleExistingTransaction方法:
        return handleExistingTransaction(definition, transaction, debugEnabled);
    }
   
    //...
}

如果是已存在事务:则需要对事务的传播属性进行处理,如下即上述截图中的的handleExistingTransaction方法

private TransactionStatus handleExistingTransaction(TransactionDefinition definition,
         Object transaction, boolean debugEnabled) throws TransactionException {
    // PROPAGATION_NEVER:不允许存在事务,如果存在抛出异常
    if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {
        throw new IllegalTransactionStateException(
                "Existing transaction found for transaction marked with propagation 'never'");
    }
    // PROPAGATION_NOT_SUPPORTED:不支持事务,如果存在事务,则需将事务挂起,保存起来,
    //      当执行完成之后,需要将挂起的事务继续恢复
    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);
    }
    //PROPAGATION_REQUIRES_NEW:开启一个新的事务,如果当前存在事务则把当前事务挂起来
    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方法,将事务开启。
            doBegin(transaction, definition);
            prepareSynchronization(status, definition);
            return status;
        } catch (RuntimeException beginEx) {
            resumeAfterBeginException(transaction, suspendedResources, beginEx);
            throw beginEx;
        } catch (Error beginErr) {
            resumeAfterBeginException(transaction, suspendedResources, beginErr);
            throw beginErr;
        }
    }

    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.
  //PROPAGATION_SUPPORTS 和 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);
}

6.2 事务的挂起

对于DataSourceTransactionManager来说,事务的挂起,就是把当前线程关联的ConnectionHolder解除绑定、同理事务的恢复就是把上述ConnectionHolder再重新绑定到当前线程,继续执行该事务。

@Override
protected Object doSuspend(Object transaction) {
    DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
    txObject.setConnectionHolder(null);
    //解除绑定dataSource, conHolder 至 TransactionSynchronizationManager
    ConnectionHolder conHolder = (ConnectionHolder)
            TransactionSynchronizationManager.unbindResource(this.dataSource);
    return conHolder;
}

@Override
protected void doResume(Object transaction, Object suspendedResources) {
    ConnectionHolder conHolder = (ConnectionHolder) suspendedResources;
    //重新绑定dataSource, conHolder 至 TransactionSynchronizationManager
    TransactionSynchronizationManager.bindResource(this.dataSource, conHolder);
}

参考文章

posted @ 2022-04-25 15:16  夏尔_717  阅读(905)  评论(0编辑  收藏  举报