Spring 事务源码分析

  • 三哥

内容来自【自学星球】

欢迎大家来了解我的星球,和星主(也就是我)一起学习 Java ,深入 Java 体系中的所有技术。我给自己定的时间是一年,无论结果如何,必定能给星球中的各位带来点东西。

想要了解更多,欢迎访问👉:自学星球

--------------SSM系列源码文章及视频导航--------------

创作不易,望三连支持!

SSM源码解析视频

👉点我

Spring

  1. Spring 中注入 Bean 的各种骚操作做
  2. Spring 中Bean的生命周期及后置处理器使用
  3. Spring 中容器启动分析之refresh方法执行之前
  4. Spring refresh 方法分析之一
  5. Spring refresh 方法之二 invokeBeanFactoryPostProcessors 方法解析
  6. Spring refresh 方法分析之三
  7. Spring refresh 方法之四 finishBeanFactoryInitialization 分析
  8. Spring AOP源码分析一
  9. Spring AOP源码分析二
  10. Spring 事务源码分析

SpringMVC

  1. SpringMVC 启动流程源码分析
  2. SpringMVC 请求流程源码分析

MyBatis

  1. MyBatis 源码分析之 SqlSessionFactory 创建
  2. MyBatis 源码分析之 SqlSession 创建
  3. MyBatis 源码分析之 Mapper 接口代理对象生成及方法执行
  4. MyBatis 源码分析之 Select 语句执行(上)
  5. MyBatis 源码分析之 Select 语句执行(下)
  6. MyBatis 源码分析一二级缓存

---------------------【End】--------------------

一、简单使用

在这里使用声明式事物案例。

1、引入依赖

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-tx</artifactId>
    <version>5.0.2.RELEASE</version>
</dependency>

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.0.2.RELEASE</version>
</dependency>
<!--mysql-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.25</version>
</dependency>
<!--阿里连接池-->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.2.8</version>
</dependency>

2、编写 JDBC 配置文件

jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/my_utils?useUnicode=true&useSSL=false&characterEncoding=utf8&allowMultiQueries=true&serverTimezone=Asia/Shanghai
jdbc.username=root
jdbc.password=root

3、编写配置类

@EnableTransactionManagement // 开启事物
@Configuration
@ComponentScan("cn.j3code.studyspring.transactional")
@PropertySource("classpath:jdbc.properties")
public class MyTransactionalConfig {

    @Value("${jdbc.driver}")
    private String driver;
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.username}")
    private String username;
    @Value("${jdbc.password}")
    private String password;

    // 数据库连接池
    @Bean
    public DruidDataSource getDataSource(){
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setUrl(url);
        druidDataSource.setDriverClassName(driver);
        druidDataSource.setUsername(username);
        druidDataSource.setPassword(password);
        return druidDataSource;
    }
    // 数据库操作对象
    @Bean
    public JdbcTemplate getJdbcTemplate(DruidDataSource druidDataSource){
        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        jdbcTemplate.setDataSource(druidDataSource);
        return jdbcTemplate;
    }
    // 事物管理器
    @Bean
    public DataSourceTransactionManager getTransactional(DruidDataSource druidDataSource){
        DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
        dataSourceTransactionManager.setDataSource(druidDataSource);
        return dataSourceTransactionManager;
    }

}

4、业务类

public interface IUserService {

    void add(User user);
    void update(User user);
}

@Service
public class UserServiceImpl implements IUserService {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Transactional // 事物注解
    @Override
    public void add(User user) {
        int update = jdbcTemplate.update("insert into t_user(name,age) values(?,?)", user.getName(), user.getAge());
        user = jdbcTemplate.queryForObject("select * from t_user where name = '" + user.getName() + "'", User.class);
        System.out.println("查询结果:" + user);
        update(user);
    }

    @Override
    public void update(User user) {
        int update = jdbcTemplate.update("update t_user set age = ? where id = ?", user.getAge(), user.getId());
    }
}

5、测试

public class MyTransactionalMain {

    public static void main(String[] args) {
        // 读取配置文件启动
        AnnotationConfigApplicationContext annotationApplicationContext =
                new AnnotationConfigApplicationContext(MyTransactionalConfig.class);


        IUserService bean = annotationApplicationContext.getBean(IUserService.class);
        User user = new User();
        user.setName("J3");
        user.setAge(18);
        bean.add(user);
    }
}

细心的同学应该知道,如果程序中不加 @EnableTransactionManagement 注解,那么我们这个测试案例中事物相关的特性就不会生效,所以下面我们就以这个为切入点开始进入事物源码的分析。

二、@EnableTransactionManagement

注解源码:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
    /**
	 * 指定使用什么代理模式(true为cglib代理,false 为jdk代理)
	 */
    boolean proxyTargetClass() default false;

    /**
	 * 通知模式 是使用代理模式还是aspectj 我们一般使用Proxy
	 */
    AdviceMode mode() default AdviceMode.PROXY;

    /**
	 * Indicate the ordering of the execution of the transaction advisor
	 * when multiple advices are applied at a specific joinpoint.
	 * <p>The default is {@link Ordered#LOWEST_PRECEDENCE}.
	 */
    int order() default Ordered.LOWEST_PRECEDENCE;
}

又看到了个非常熟悉的 @Import 注解,向 IOC 容器中导入 TransactionManagementConfigurationSelector 类。

该类源码:

public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {

    @Override
    protected String[] selectImports(AdviceMode adviceMode) {
        switch (adviceMode) {
                // 如果基于代理模式
            case PROXY:
                return new String[] {AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()};
                // 如果基于ASPECTJ
            case ASPECTJ:
                return new String[] {TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME};
            default:
                return null;
        }
    }

}

因为 @EnableTransactionManagement 注解如果不设置 mode ,则使用默认的 PROXY 模式,反之则是 ASPECTJ 模式。

这里,我们只讨论代理的方式实现事物,所以会走下面这个代码。

return new String[] {AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()};

2.1 AutoProxyRegistrar

先来看看 AutoProxyRegistrar 源码:

public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar {

    private final Log logger = LogFactory.getLog(getClass());

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        boolean candidateFound = false;
        // 从我们传入进去的配置类上获取所有的注解的
        Set<String> annoTypes = importingClassMetadata.getAnnotationTypes();
        // 循环我们上一步获取的注解
        for (String annoType : annoTypes) {
            // 获取注解的元信息
            AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annoType);
            if (candidate == null) {
                continue;
            }
            // 获取注解的mode属性
            Object mode = candidate.get("mode");
            // 获取注解的proxyTargetClass
            Object proxyTargetClass = candidate.get("proxyTargetClass");
            // 根据mode和proxyTargetClass的判断来注册不同的组件
            if (mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() &&
                Boolean.class == proxyTargetClass.getClass()) {
                candidateFound = true;
                if (mode == AdviceMode.PROXY) {
                    // 重点进入到这一步
                    AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
                    if ((Boolean) proxyTargetClass) {
                        AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
                        return;
                    }
                }
            }
        }
        if (!candidateFound && logger.isInfoEnabled()) {
            String name = getClass().getSimpleName();
            logger.info(String.format("%s was imported but no annotations were found " +
                                      "having both 'mode' and 'proxyTargetClass' attributes of type " +
                                      "AdviceMode and boolean respectively. This means that auto proxy " +
                                      "creator registration and configuration may not have occurred as " +
                                      "intended, and components may not be proxied as expected. Check to " +
                                      "ensure that %s has been @Import'ed on the same class where these " +
                                      "annotations are declared; otherwise remove the import of %s " +
                                      "altogether.", name, name, name));
        }
    }

}

该方法会获取传入进来的 class 上标注的注解,并循环获取到的注解进行判断,如果是事物相关的注解则会进入 registerAutoProxyCreatorIfNecessary 方法,该方法会向容器中注册事物自动代理创建器类。

进入registerAutoProxyCreatorIfNecessary 方法源码:

org.springframework.aop.config.AopConfigUtils#registerAutoProxyCreatorIfNecessary

public static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
   return registerAutoProxyCreatorIfNecessary(registry, null);
}

org.springframework.aop.config.AopConfigUtils#registerAutoProxyCreatorIfNecessary

public static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry,
                                                                 @Nullable Object source) {
    // 注册自动代理创建器
    return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source);
}

在 AOP 中向容器中注册的自动代理创建器是 AnnotationAwareAspectJAutoProxyCreator ,而在此事物自动创建代理器则是 InfrastructureAdvisorAutoProxyCreator 。

在 AopConfigUtils 中标注了所有支持的自动代理创建类,根据其代码可以判断优先级如下:

代码

public abstract class AopConfigUtils {
    private static final List<Class<?>> APC_PRIORITY_LIST = new ArrayList<>();

    /**
 * Setup the escalation list.
 */
    static {
        APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class);
        APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class);
        APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class);
    }
}

优先级:

InfrastructureAdvisorAutoProxyCreator < AspectJAwareAdvisorAutoProxyCreator < AnnotationAwareAspectJAutoProxyCreator

下面我们来看看 InfrastructureAdvisorAutoProxyCreator 的类继承结构图

在这里插入图片描述

由图可知,该类实现了 BeanPostProcessor 接口,则其会作用于每个 Bean 的初始化前后。在每个 bean 初始化前调用 postProcessBeforeInitialization,初始化后调用 postProcessAfterInitialization 。

2.2 ProxyTransactionManagementConfiguration

该类源码:

public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {

    /**
	* 为我我们容器中导入了 
	* beanName为org.springframework.transaction.config.internalTransactionAdvisor 
	* 类型为BeanFactoryTransactionAttributeSourceAdvisor
	* 的增强器
	*/
    @Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
        BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
        advisor.setTransactionAttributeSource(transactionAttributeSource());
        advisor.setAdvice(transactionInterceptor());
        if (this.enableTx != null) {
            advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
        }
        return advisor;
    }

    /** 
	* 定义了一个事物属性源对象 
	*/
    @Bean
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    public TransactionAttributeSource transactionAttributeSource() {
        return new AnnotationTransactionAttributeSource();
    }

    /** 
	* 事物拦截器对象 
	*/
    @Bean
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    public TransactionInterceptor transactionInterceptor() {
        TransactionInterceptor interceptor = new TransactionInterceptor();
        // 把事物属性源对象设置到我们的事物拦截器对象中
        interceptor.setTransactionAttributeSource(transactionAttributeSource());
        if (this.txManager != null) {
            // 把我们容器中的 事物对象配置到事物拦截器中
            interceptor.setTransactionManager(this.txManager);
        }
        return interceptor;
    }

}

ProxyTransactionManagementConfiguration 很明显就是一个事物相关的配置类,该类向 IOC 容器中注册了三个 bean:

  • BeanFactoryTransactionAttributeSourceAdvisor:增强器
  • TransactionAttributeSource:事物属性源
  • TransactionInterceptor:事物拦截器

可以说,事物相关的功能离不开这三个类的互相作用,下面依次分析这三个类。

2.2.1 BeanFactoryTransactionAttributeSourceAdvisor

先看一下该类继承结构图:

在这里插入图片描述

BeanFactoryTransactionAttributeSourceAdvisorAdvisor 子类,那么我们可以知道其中有两个关键属性: Pointcut(判断是否可以作用于当前方法)Advice(作用于当前方法的具体逻辑)

那我们来看看 Pointcut 是如何生效的。

再分析 Pointcut 生效前,我们先明确一件事情,Spring 事物也是通过 AOP 代理的方式实现的。那么要判断一个 Bean 是否需要代理,肯定也是走 AOP 代理的流程,通过遍历程序中所有的增强对象进行挨个判断,匹配了那么就是需要进行代理。

那,这就回顾到 AOP 代理的流程了,循环程序中的增强对象进行挨个判断的程序如下:

org.springframework.aop.support.AopUtils#findAdvisorsThatCanApply

public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {

    // ...
    
    // 循环程序中的所有增强对象
    for (Advisor candidate : candidateAdvisors) {
        if (candidate instanceof IntroductionAdvisor) {
            // already processed
            continue;
        }
        // 挨个判断增强是否生效
        if (canApply(candidate, clazz, hasIntroductions)) {
            eligibleAdvisors.add(candidate);
        }
    }

    // ...

}

canApply 最终会通过调用 Pointcut 中的 matches 方法进行判断,那么怎会来到我们事物增强对象中的这个代理:

public class BeanFactoryTransactionAttributeSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor {

    // 初始化事物增强判断对象 pointcut
    private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {
        @Override
        @Nullable
        protected TransactionAttributeSource getTransactionAttributeSource() {
            return transactionAttributeSource;
        }
    };

}

org.springframework.transaction.interceptor.TransactionAttributeSourcePointcut#matches

public boolean matches(Method method, @Nullable Class<?> targetClass) {
    if (targetClass != null && TransactionalProxy.class.isAssignableFrom(targetClass)) {
        return false;
    }
    // 获取 ProxyTransactionManagementConfiguration 配置类中配置的 AnnotationTransactionAttributeSource 对象
    TransactionAttributeSource tas = getTransactionAttributeSource();
    // 调用 AnnotationTransactionAttributeSource # getTransactionAttribute 方法进行事物解析
    return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
}

我们可以看到最终会调用 getTransactionAttribute 方法,如果该方法返回一个对象说明该方法或 class 需要增强。

2.2.2 AnnotationTransactionAttributeSource

该类继承结构图如下:

在这里插入图片描述

由 2.2.1 节可知,matches 方法会调用其 getTransactionAttribute 方法来找到类或方法的事物相关功能,而我们再源码中并没有发现 getTransactionAttribute ,而是在其父类 AbstractFallbackTransactionAttributeSource 中找到该方法的调用。

源码:

org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource#getTransactionAttribute

public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
    if (method.getDeclaringClass() == Object.class) {
        // 如果目标方法是内置类Object上的方法,总是返回null,这些方法上不应用事务
        return null;
    }

    // 先查看针对该方法是否已经获取过其注解事务属性并且已经缓存
    Object cacheKey = getCacheKey(method, targetClass);
    TransactionAttribute cached = this.attributeCache.get(cacheKey);
    if (cached != null) {
        // 目标方法上的事务注解属性信息已经缓存的情况
        // or an actual transaction attribute.
        if (cached == NULL_TRANSACTION_ATTRIBUTE) {
            // 目标方法上上并没有事务注解属性,但是已经被尝试分析过并且已经被缓存,
            // 使用的值是 NULL_TRANSACTION_ATTRIBUTE,所以这里再次尝试获取其注解事务属性时,
            // 直接返回 null
            return null;
        }
        else {
            // 返回所缓存的注解事务属性
            return cached;
        }
    }
    else {
        // 目标方法上的注解事务属性尚未分析过,现在分析获取
        TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass);
        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 方法进行查找,最后放入缓存并返回结果。

那么,接下来就看看 computeTransactionAttribute 方法源码:

org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource#computeTransactionAttribute

protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
    // 如果事务注解属性分析仅仅针对public方法,而当前方法不是public,则直接返回null
    if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
        return null;
    }

    // Ignore CGLIB subclasses - introspect the actual user class.
    // 参数 method 可能是基于接口的方法,该接口和参数targetClass所对应的类不同(也就是说:
    // targetClass是相应接口的某个实现类),而我们这里需要的属性是要来自targetClass的,
    // 所以这里先获取targetClass上的那个和method对应的方法,这里 method, specificMethod 
    // 都可以认为是潜在的目标方法
    Class<?> userClass = (targetClass != null ? ClassUtils.getUserClass(targetClass) : 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 = ClassUtils.getMostSpecificMethod(method, userClass);
    // If we are dealing with method with generic parameters, find the original method.
    specificMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);

    // 首先尝试检查事务注解属性直接标记在目标方法 specificMethod 上
    TransactionAttribute txAttr = findTransactionAttribute(specificMethod);
    if (txAttr != null) {
        // 事务注解属性直接标记在目标方法上
        return txAttr;
    }

    // 然后尝试检查事务注解属性是否标记在目标方法 specificMethod 所属类上
    txAttr = findTransactionAttribute(specificMethod.getDeclaringClass());
    if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
        // 事务注解属性是否标记在目标方法所属类上
        return txAttr;
    }

    // 逻辑走到这里说明目标方法specificMethod,也就是实现类上的目标方法上没有标记事务注解属性
    if (specificMethod != method) {
        // 如果 specificMethod 和 method 不同,则说明 specificMethod 是具体实现类
        // 的方法,method 是实现类所实现接口的方法,现在尝试从 method 上获取事务注解属性
        txAttr = findTransactionAttribute(method);
        if (txAttr != null) {
            return txAttr;
        }
        // 现在尝试在 method 所属类上查看是否有事务注解属性
        txAttr = findTransactionAttribute(method.getDeclaringClass());
        if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
            return txAttr;
        }
    }
    // specificMethod 方法/所属类上没有事务注解属性,
    // method 方法/所属类上也没有事务注解属性,
    // 所以返回 null
    return null;
}

该方法分类很多种类型获取事物注解属性:

  • 目标方法上
  • 目标方法所属类上
  • 目标接口方法上
  • 目标接口方法所属类上

以上这四种,有一个找到事物相关属性则直接返回。那么具体是如何找的,就要进入 findTransactionAttribute 方法具体看看了。

org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#findTransactionAttribute(java.lang.reflect.Method)

protected TransactionAttribute findTransactionAttribute(Method method) {
    return determineTransactionAttribute(method);
}

org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#determineTransactionAttribute

/**
	 * 分析获取某个被注解的元素,具体的来讲,指的是一个类或者一个方法上的事务注解属性。
	 * 该实现会遍历自己属性annotationParsers中所包含的事务注解属性分析器试图获取事务注解属性,
	 * 一旦获取到事务注解属性则返回,如果获取不到则返回null,表明目标类/方法上没有事务注解。
	 */
protected TransactionAttribute determineTransactionAttribute(AnnotatedElement ae) {
    for (TransactionAnnotationParser annotationParser : this.annotationParsers) {
        TransactionAttribute attr = annotationParser.parseTransactionAnnotation(ae);
        if (attr != null) {
            return attr;
        }
    }
    return null;
}

org.springframework.transaction.annotation.SpringTransactionAnnotationParser#parseTransactionAnnotation(java.lang.reflect.AnnotatedElement)

public TransactionAttribute parseTransactionAnnotation(AnnotatedElement ae) {
    // 查找 ae 对象上是否由 Transactional.class 相关信息
    AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes(
        ae, Transactional.class, false, false);
    // 存在 Transactional 注解信息
    if (attributes != null) {
        // 封装 Transactional 注解信息,并返回
        return parseTransactionAnnotation(attributes);
    }
    else {
        return null;
    }
}

在这里我们看到了最想看到的东西了,就是判断是否有 Transactional 注解标注的信息,如果有 findMergedAnnotationAttributes 方法会返回其对应的对象,并通过 parseTransactionAnnotation 解析该对象然后返回封装的结果。

org.springframework.transaction.annotation.SpringTransactionAnnotationParser#parseTransactionAnnotation(org.springframework.core.annotation.AnnotationAttributes)

protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {
    //这个地方事务属性对象是有很多默认值的,它继承自DefaultTransactionDefinition
    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"));
    // 事务管理器bean的名称
    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;
}

到这里,事务相关的信息已经被解析完成存放在 AnnotationTransactionAttributeSource 类体系当中了。而且有对象返回在 matches 方法中就会返回 true ,最后会走创建代理流程,至此我们的事务代理对象就完成了。

下面就是事务代理的执行了,在 TransactionInterceptor # invoke 方法中。

2.2.3 TransactionInterceptor

该类继承结构图:

在这里插入图片描述

TransactionInterceptor 是事务拦截器,当标注 @Transaction 注解的方法被执行时会来执行 invoke 方法,源码如下:

public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {

    @Override
    @Nullable
    public Object invoke(final MethodInvocation invocation) throws Throwable {

        // 获取代理对象的目标class
        Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);

        // 使用事务调用
        return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
    }

}

进入 invokeWithinTransaction 方法:

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

    // 获取事务数据源,这里获取的数据源就是在  TransactionInterceptor 注入的时候的设置的属性transactionAttributeSource = AnnotationTransactionAttributeSource。
    // 在 ProxyTransactionManagementConfiguration 中完成	
    TransactionAttributeSource tas = getTransactionAttributeSource();
    // 获取对应的事务属性
    final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
    // 获取一个合适的 TransactionManager 
    final PlatformTransactionManager tm = determineTransactionManager(txAttr);
    // 构造方法的唯一标识( 全路径了类名.方法)
    final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
    // 对不同事务情景的处理
    // 声明式事务的处理
    // 如果txAttr为空或者tm 属于非CallbackPreferringPlatformTransactionManager,执行目标增强
    // 在TransactionManager上,CallbackPreferringPlatformTransactionManager实现PlatformTransactionManager接口,暴露出一个方法用于执行事务处理中的回调
    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;
    }
    // 编程式事务(CallbackPreferringPlatformTransactionManager)的处理。这里的逻辑基本都被封装了
    else {
        final ThrowableHolder throwableHolder = new ThrowableHolder();

        // It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
        try {
            // 直接调用execute 方法。由于事务的提交回滚等操作都已经封装好了,所以这里并没有对事务进行详细的操作。
            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;
        }
    }
}

invokeWithinTransaction 方法分为两种情况执行:

  • 声明式事务
  • 编程式事务

这里,我们主要分析声明式事务的情况进行分析,所以主要就是一下几个步骤:

  1. createTransactionIfNecessary():创建事务(这里可能创建也可能不创建)
  2. invocation.proceedWithInvocation():执行目标方法
  3. completeTransactionAfterThrowing(txInfo, ex):异常,执行提交事务或回滚事务
  4. cleanupTransactionInfo(txInfo):清理当前线程事务信息
  5. commitTransactionAfterReturning(txInfo):方法执行成功,提交事务

三、事务执行流程

3.1 事务创建

源码:

org.springframework.transaction.interceptor.TransactionAspectSupport#createTransactionIfNecessary

// 若有需要 创建一个TransactionInfo (具体的事务从事务管理器里面getTransaction()出来~)
protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,
                                                       @Nullable TransactionAttribute txAttr, final String joinpointIdentification) {

    // If no name specified, apply method identification as transaction name.
    // 如果没有名称指定则使用方法唯一标识,并使用 DelegatingTransactionAttribute 包装 txAttr
    if (txAttr != null && txAttr.getName() == null) {
        txAttr = new DelegatingTransactionAttribute(txAttr) {
            @Override
            public String getName() {
                return joinpointIdentification;
            }
        };
    }
    // 从事务管理器里,通过txAttr拿出来一个TransactionStatus
    TransactionStatus status = null;
    if (txAttr != null) {
        if (tm != null) {
            // 获取 TransactionStatus
            status = tm.getTransaction(txAttr);
        }
        else {
            if (logger.isDebugEnabled()) {
                logger.debug("Skipping transactional joinpoint [" + joinpointIdentification +
                             "] because no transaction manager has been configured");
            }
        }
    }
    // 根据指定的属性与 status 等,转换成一个通用的TransactionInfo
    return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
}

这个方法有两个逻辑:

  • 获取事务状态
  • 封装事务信息

先来看一下事务状态有哪些

DefaultTransactionStatus 是 TransactionStatus 的默认实现

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

再来看看事务传播值有哪些

public interface 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;
    // 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。
    int PROPAGATION_NESTED = 6;

    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;

    // (串行化)完全服从acid隔离原则,确保不发生脏读、不可重复读、和幻读,但执行效率最低。
    int ISOLATION_SERIALIZABLE = Connection.TRANSACTION_SERIALIZABLE;

    // 使用数据库默认的事务隔离级别。
    int TIMEOUT_DEFAULT = -1;
}

ok,简单了解了这些相关内容之后,那我们来看看是如何获取事务状态信息的。

org.springframework.transaction.support.AbstractPlatformTransactionManager#getTransaction

public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
    throws TransactionException {

    // 注解的信息
    TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());
    // 得到事务的封装对象
    //doGetTransaction()方法是抽象方法,具体的实现由具体的事务处理器提供(下面会以DataSourceTransactionManager为例子)
    Object transaction = doGetTransaction();
    boolean debugEnabled = logger.isDebugEnabled();

    //检查当前线程是否存在事务  isExistingTransaction此方法默认返回false  但子类都复写了此方法
    if (isExistingTransaction(transaction)) {
        // Existing transaction found -> check propagation behavior to find out how to behave.
        // handleExistingTransaction方法为处理已经存在事务的情况
        // 这个方法的实现也很复杂,总之还是对一些传播属性进行解析,各种情况的考虑~~~~~ 如果有新事务产生 doBegin()就会被调用~~~~
        return handleExistingTransaction(def, transaction, debugEnabled);
    }

    // 如果注解设置的参数是不合法,抛异常
    if (def.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
        throw new InvalidTimeoutException("Invalid transaction timeout", def.getTimeout());
    }

    // 处理事务属性中配置的事务传播特性==============

    // PROPAGATION_MANDATORY 如果已经存在一个事务,支持当前事务。如果没有一个活动的事务,则抛出异常
    if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
        throw new IllegalTransactionStateException(
            "No existing transaction found for transaction marked with propagation 'mandatory'");
    }
    //如果事务传播特性为required、required_new或nested
    else if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
             def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
             def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {

        // 挂起,但是doSuspend()由子类去实现~~~
        // 挂起操作,触发相关的挂起注册的事件,把当前线程事物的所有属性都封装好,放到一个SuspendedResourcesHolder
        // 然后清空清空一下`当前线程事务`
        SuspendedResourcesHolder suspendedResources = suspend(null);
        if (debugEnabled) {
            logger.debug("Creating new transaction with name [" + def.getName() + "]: " + def);
        }
        try {
            boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
            //创建一个新的事务状态  就是new DefaultTransactionStatus()  把个属性都赋值上
            DefaultTransactionStatus status = newTransactionStatus(
                definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
            // 开启事物,抽象方法,由子类去实现~
            doBegin(transaction, definition);
            // 初始化事物同步属性
            //初始化和同步事务状态 是TransactionSynchronizationManager这个类  它内部维护了很多的ThreadLocal
            prepareSynchronization(status, definition);
            return status;
        }
        catch (RuntimeException | Error ex) {
            //重新开始 doResume由子类去实现
            resume(null, suspendedResources);
            throw ex;
        }
    }

    // 走到这里  传播属性就是不需要事务的  那就直接创建一个
    else {
        // Create "empty" transaction: no actual transaction, but potentially synchronization.
        if (def.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) {
            logger.warn("Custom isolation level specified but no actual transaction initiated; " +
                        "isolation level will effectively be ignored: " + def);
        }
        // 这个方法相当于先newTransactionStatus,再prepareSynchronization这两步~~~
        // 显然和上面的区别是:中间不回插入调用doBegin()方法,因为没有事务  begin个啥
        boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
        return prepareTransactionStatus(def, null, true, newSynchronization, debugEnabled, null);
    }
}

总结一下该方法干了些啥:

  1. 获取事务封装对象
  2. 判断是否存在事务,存在则走事务存在逻辑
  3. 处理事务属性中配置的事务传播特性
    • PROPAGATION_MANDATORY 情况下,抛错
    • PROPAGATION_REQUIRED、PROPAGATION_REQUIRES_NEW 、PROPAGATION_NESTED 情况下
      • 挂起空事务
      • 新建一个事务
    • 以非事务方式运行

接着,我们先来看看获取事务封装对象方法 doGetTransaction()

org.springframework.jdbc.datasource.DataSourceTransactionManager#doGetTransaction

protected Object doGetTransaction() {
    // 新建一个事务的封装对象,主要是保存Connenct;
    DataSourceTransactionObject txObject = new DataSourceTransactionObject();
    txObject.setSavepointAllowed(isNestedTransactionAllowed());
    // 通过事务事务同步器,得到曾经绑定的连接connect;
    ConnectionHolder conHolder =
        (ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
    txObject.setConnectionHolder(conHolder, false);
    return txObject;
}

TransactionSynchronizationManager 中都是用 ThreadLocal 进行存值。

下面看看判断是否存在事务方法 isExistingTransaction():

org.springframework.jdbc.datasource.DataSourceTransactionManager#isExistingTransaction

protected boolean isExistingTransaction(Object transaction) {
    DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
    return (txObject.hasConnectionHolder() && txObject.getConnectionHolder().isTransactionActive());
}

在事务封装的对象中有connect,连接的信息。如果是正在使用的事务,这个属性是true。

如果事务存在,那么则会进行 Spring 事务的传播行为逻辑中,对每个具体的传播行为做处理,方法为 handleExistingTransaction() 。

org.springframework.transaction.support.AbstractPlatformTransactionManager#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'");
    }

    // 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
    if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
        if (debugEnabled) {
            logger.debug("Suspending current transaction");
        }
        // 重点:挂起已有事物
        Object suspendedResources = suspend(transaction);
        boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
        // 创建新事物,注意:transaction参数为null,所以这里创建的不是一个真正的事物
        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() + "]");
        }
        // 下面对JtaTransactionManager和AbstractPlatformTransactionManager分别进行处理
        // useSavepointForNestedTransaction(),是否为嵌套事务使用保存点
        // 对于JtaTransactionManager-->返回false
        // 对于AbstractPlatformTransactionManager-->返回true
        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.
            // 创建保存点在现有spring管理事务,通过TransactionStatus SavepointManager API实现。
            // 通常使用JDBC 3.0保存点。永远不要激活Spring同步。
            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.
            // 通过嵌套的开始,提交调用,及回滚调用进行嵌套事务。
            // 只对JTA有效,如果已经存在JTA事务,这里可能会激活Spring同步。
            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);
}

总结一下这个方法干了啥:

  • 当前事务传播行为等于 PROPAGATION_NEVER,则报错
  • 当前事务传播行为等于 PROPAGATION_NOT_SUPPORTED,则挂起事务,走没有事务的逻辑
  • 当前事务传播行为等于 PROPAGATION_REQUIRES_NEW,则创建个新的,老事务挂起
  • 当前事务传播行为等于 PROPAGATION_NESTED,则嵌套事务使用,保存点,也就是说回滚也是回滚本方法得到
  • 剩下的就是使用当前事务

这其中有几个重要方法我们要拿出来分析分析:

1、挂起当前事务,记录当前事务状态,以便后续的恢复操作

org.springframework.transaction.support.AbstractPlatformTransactionManager#suspend

protected final SuspendedResourcesHolder suspend(@Nullable Object transaction) throws TransactionException {
    // 1.如果存在事物同步回调接口
    if (TransactionSynchronizationManager.isSynchronizationActive()) {
        // 1.1 挂起事务同步回调接口
        List<TransactionSynchronization> suspendedSynchronizations = doSuspendSynchronization();
        try {
            // 挂起事物
            Object suspendedResources = null;
            if (transaction != null) {
                suspendedResources = doSuspend(transaction);
            }
            // 获取已有事物名称
            String name = TransactionSynchronizationManager.getCurrentTransactionName();
            // 清空已有事物名称
            TransactionSynchronizationManager.setCurrentTransactionName(null);
            // 获取已有事物的readOnly属性值
            boolean readOnly = TransactionSynchronizationManager.isCurrentTransactionReadOnly();
            // 将已有事物的readOnly属性值设置为false
            TransactionSynchronizationManager.setCurrentTransactionReadOnly(false);
            // 获取已有事物数据库事物隔离级别
            Integer isolationLevel = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel();
            // 清空已有事物数据库事物隔离级别
            TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(null);
            // 获取已有事物激活标识
            boolean wasActive = TransactionSynchronizationManager.isActualTransactionActive();
            // 将当前事物激活标识设置为false
            TransactionSynchronizationManager.setActualTransactionActive(false);
            // 将上面获取到的一系列事物属性,重新封装至SuspendedResourcesHolder对象,并返回
            return new SuspendedResourcesHolder(
                suspendedResources, suspendedSynchronizations, name, readOnly, isolationLevel, wasActive);
        }
        catch (RuntimeException | Error ex) {
            // doSuspend failed - original transaction is still active...
            doResumeSynchronization(suspendedSynchronizations);
            throw ex;
        }
    }
    // 不存在事物同步回调接口,且当前事物不为空
    else if (transaction != null) {
        // Transaction active but no synchronization active.
        // 事物已经被激活,但是没有事物同步回调,则直接挂起当前事物即可
        Object suspendedResources = doSuspend(transaction);
        // 返回挂起的事物资源
        return new SuspendedResourcesHolder(suspendedResources);
    }
    // 处理没有事物的情况...
    else {
        // Neither transaction nor synchronization active.
        return null;
    }
}

2、新建事务

org.springframework.jdbc.datasource.DataSourceTransactionManager#doBegin

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

    try {
        if (!txObject.hasConnectionHolder() ||
            txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
            // 从DataSource里获取一个连接(这个DataSource一般是有连接池的)
            Connection newCon = obtainDataSource().getConnection();
            if (logger.isDebugEnabled()) {
                logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
            }
            // 把这个链接用ConnectionHolder包装一下
            txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
        }

        txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
        con = txObject.getConnectionHolder().getConnection();
        // 设置isReadOnly、设置隔离界别等
        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).
        // 这里非常的关键,先看看Connection 是否是自动提交的
        // 如果是 就con.setAutoCommit(false)  要不然数据库默认没执行一条SQL都是一个事务,就没法进行事务的管理了
        if (con.getAutoCommit()) {
            txObject.setMustRestoreAutoCommit(true);
            if (logger.isDebugEnabled()) {
                logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
            }
            //开启事务,设置autoCommit为false
            con.setAutoCommit(false);
        }
        // ====因此从这后面,通过此Connection执行的所有SQL语句只要没有commit就都不会提交给数据库的=====

        // 这个方法特别特别有意思   它自己`Statement stmt = con.createStatement()`拿到一个Statement
        // 然后执行了一句SQL:`stmt.executeUpdate("SET TRANSACTION READ ONLY");`
        // 所以:如果你仅仅只是查询。把事务的属性设置为readonly=true  Spring对帮你对SQl进行优化的
        // 需要注意的是:readonly=true 后,只能读,不能进行dml操作)
        // (只能看到设置事物前数据的变化,看不到设置事物后数据的改变)
        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()) {
            //这里将当前的connection放入TransactionSynchronizationManager中持有,如果下次调用可以判断为已有的事务
            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);
    }
}

总结该方法干了些啥:

  • 尝试获取连接
  • 设置隔离级别及只读标识
  • 更改默认的提交设置
  • 设置标志位,标识当前连接已经被事务激活
  • 设置过期时间
  • 将 connectionHolder 绑定到当前线程

最后,我们回到 getTransaction 方法,当不存在事务时,则执行流程与 handleExistingTransaction 方法的后半段类似。

下面我们再次回到 createTransactionIfNecessary 来看看 prepareTransactionInfo 方法,准备事务信息。

org.springframework.transaction.interceptor.TransactionAspectSupport#prepareTransactionInfo

protected TransactionInfo prepareTransactionInfo(@Nullable PlatformTransactionManager tm,
                                                 @Nullable TransactionAttribute txAttr, String joinpointIdentification,
                                                 @Nullable TransactionStatus status) {

    // 构造一个TransactionInfo 
    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.
        // 如果已存在不兼容的Tx,设置status
        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.
    // 这句话是最重要的:把生成的TransactionInfo并绑定到当前线程的ThreadLocal
    txInfo.bindToThread();
    return txInfo;
}

该方法创建一个 TransactionInfo 类型对象,它记录了事务的所有信息。当事务执行失败或成功时,会从这里获取相关信息执行对应逻辑。

3.2 目标方法执行

retVal = invocation.proceedWithInvocation();

这个代码可以理解就是去执行我们的业务方法,其内部是调用 AOP 的执行链,进而会调用 ReflectiveMethodInvocation#proceed 方法。

3.3 异常情况(提交或回滚事务)

completeTransactionAfterThrowing(txInfo, ex);

如果执行业务方法出错,会进入这个方法判断是回滚还是提交事务。

org.springframework.transaction.interceptor.TransactionAspectSupport#completeTransactionAfterThrowing

protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex) {
    if (txInfo != null && txInfo.getTransactionStatus() != null) {
        if (logger.isTraceEnabled()) {
            logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() +
                         "] after exception: " + ex);
        }
        if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {
            try {
                // 异常类型为回滚异常,执行事务回滚
                txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
            }
            catch (TransactionSystemException ex2) {
                logger.error("Application exception overridden by rollback exception", ex);
                ex2.initApplicationException(ex);
                throw ex2;
            }
            catch (RuntimeException | Error ex2) {
                logger.error("Application exception overridden by rollback exception", ex);
                throw ex2;
            }
        }
        else {

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

该方法要注意的就是如果设置了回滚的异常类型,那么在回滚之前会判断报错类型是否是指定的回滚类型,如果是则回滚,否则提交事务。

3.4 提交事务

commitTransactionAfterReturning(txInfo);

方法源码

org.springframework.transaction.interceptor.TransactionAspectSupport#commitTransactionAfterReturning

protected void commitTransactionAfterReturning(@Nullable TransactionInfo txInfo) {
    if (txInfo != null && txInfo.getTransactionStatus() != null) {
        if (logger.isTraceEnabled()) {
            logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() + "]");
        }
        // 提交事务
        txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
    }
}

这个方法很简单,就是提交事务,底层调用的也是 Connection 中的 commit() 方法。

最后在额外看看这个清除事务信息方法:

cleanupTransactionInfo(txInfo);

org.springframework.transaction.interceptor.TransactionAspectSupport#cleanupTransactionInfo

protected void cleanupTransactionInfo(@Nullable TransactionInfo txInfo) {
    if (txInfo != null) {
        // 清理当前线程事务信息,如果有挂起事务则将挂起事务设置到当前线程上
        txInfo.restoreThreadLocalStatus();
    }
}

因为当前事务执行完毕了,所以需要将当前线程上的事务信息清空调用,然后获取到挂起的线程,并将挂起的线程再次设置到当前线程上,如果没有挂起线程则设置 null。

最后,画图小能手上线,Spring事务执行流程图如下:

在这里插入图片描述

至此,我们的事务相关内容就分析完毕了,撒花、撒花!

好了,今天的内容到这里就结束了,我是 【J3】关注我,我们下期见


  • 由于博主才疏学浅,难免会有纰漏,假如你发现了错误或偏见的地方,还望留言给我指出来,我会对其加以修正。

  • 如果你觉得文章还不错,你的转发、分享、点赞、留言就是对我最大的鼓励。

  • 感谢您的阅读,十分欢迎并感谢您的关注。

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

J3code

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值