SpringBoot 源码解析 (八)----- Spring Boot 精髓:事务源码解析

目录

 

正文

本篇来讲一下 SpringBoot 是怎么自动开启事务的,我们先来回顾一下以前 SSM 中是如何使用事务的

回到顶部

SSM 使用事务

导入 JDBC 依赖包

众所周知,凡是需要跟数据库打交道的,基本上都要添加 jdbc 的依赖,在 Spring 项目中,加入的是 spring-jdbc 依赖:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
</dependency>

配置版事务

在使用配置文件的方式中,通常会在 Spring 的配置文件中配置事务管理器,并注入数据源:

<!-- 注册数据源 -->
<bean id="dataSource" class="...">
    <property name="" value=""/>
</bean>

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

<!-- 开启事务注解 -->
<tx:annotation-driven transaction-manager="txManager" />

接下来可以直接在业务层 Service 的方法上或者类上添加@Transactional

注解版事务

首先需要注册两个 Bean,分别对应上面 Spring 配置文件中的两个 Bean:

@EnableTransactionManagement//重要
@Configuration
public class TxConfig {
@Bean
</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> DataSource dataSource() {
    ComboPooledDataSource dataSource </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> ComboPooledDataSource();
    dataSource.setUser(</span>"..."<span style="color: rgba(0, 0, 0, 1)">);
    dataSource.setPassword(</span>"..."<span style="color: rgba(0, 0, 0, 1)">);
    dataSource.setDriverClass(</span>"..."<span style="color: rgba(0, 0, 0, 1)">);
    dataSource.setJdbcUrl(</span>"..."<span style="color: rgba(0, 0, 0, 1)">);
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> dataSource;
}

</span><strong><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">重要</span>

@Bean
public PlatformTransactionManager platformTransactionManager() {
return new DataSourceTransactionManager(dataSource());//放入数据源
}
}

我们看到往 Spring 容器中注入了 DataSource 和 PlatformTransactionManager 对象,并且通过 @EnableTransactionManagement 注解开启了事务,和上面的 XML 配置是一一对应的。PlatformTransactionManager 这个 Bean 非常重要,要使用事务管理,就必须要在 IOC 容器中注册一个事务管理器。

public interface PlatformTransactionManager {
    //获取一个 Transaction
    TransactionStatus getTransaction(TransactionDefinition var1) throws TransactionException;
    //提交事务
    void commit(TransactionStatus var1) throws TransactionException;
    //回滚事务
    void rollback(TransactionStatus var1) throws TransactionException;
}

我们看到事务管理器的作用就是获取事务,提交回滚事务。DataSourceTransactionManager 是 PlatformTransactionManager 的一个实现类,大家可以看看我以前的文章spring5 源码深度解析 ----- Spring 事务 是怎么通过 AOP 实现的?(100% 理解 Spring 事务) 看一下 Spring 的声明式事务的源码。下面我们来看看 SpringBoot 是如何自动配置事务的

回到顶部

SpringBoot 自动配置事务

引入 JDBC

众所周知,在 SpringBoot 中凡是需要跟数据库打交道的,基本上都要显式或者隐式添加 jdbc 的依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>

也就是 jdbc 的场景启动器,我们点进去看看

其实也是引入了spring-jdbc的依赖,接下来我们要看两个重要的事务自动配置类

回到顶部

DataSourceTransactionManagerAutoConfiguration

我们看到在 spring.factories 中配置了事务管理器自动配置类 DataSourceTransactionManagerAutoConfiguration,我们进去看看

 1 @Configuration
 2 //在类路径下有这个类存在 PlatformTransactionManager 时,这个配置类才会生效
 3 //而前面我们已经引入了 spring-boot-starter-jdbc,那自然是存在了
 4 @ConditionalOnClass({ JdbcTemplate.class, PlatformTransactionManager.class })
 5 @AutoConfigureOrder(Ordered.LOWEST_PRECEDENCE)
 6 @EnableConfigurationProperties(DataSourceProperties.class)
 7 public class DataSourceTransactionManagerAutoConfiguration {
 8 
 9     @Configuration
10     @ConditionalOnSingleCandidate(DataSource.class)
11     static class DataSourceTransactionManagerConfiguration {
12 
13         private final DataSource dataSource;
14 
15         private final TransactionManagerCustomizers transactionManagerCustomizers;
16 
17         DataSourceTransactionManagerConfiguration(DataSource dataSource,
18                 ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers) {
19             this.dataSource = dataSource;
20             this.transactionManagerCustomizers = transactionManagerCustomizers
21                     .getIfAvailable();
22         }
23 
24         @Bean
25         //没有当 Spring 容器中不存在 PlatformTransactionManager 这个对象时,创建 DataSourceTransactionManager
26         //也就是如果我们自定义了 DataSourceTransactionManager 并注入 Spring 容器,这里将不会执行
27         @ConditionalOnMissingBean(PlatformTransactionManager.class)
28         public DataSourceTransactionManager transactionManager(DataSourceProperties properties) {
29             //创建 DataSourceTransactionManager 注入 Spring 容器,并且把 dataSource 传进去
30             DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(this.dataSource);
31             if (this.transactionManagerCustomizers != null) {
32                 this.transactionManagerCustomizers.customize(transactionManager);
33             }
34             return transactionManager;
35         }
36 
37     }
38 
39 }

很明显只要我们导入了spring-boot-starter-jdbc 场景启动器,并且我们没有自定义 DataSourceTransactionManager,那么事务管理器自动配置类 DataSourceTransactionManagerAutoConfiguration 会自动为我们创建 DataSourceTransactionManager 并注入 Spring 容器中。但是这还不够,我们前面还是需要通过@EnableTransactionManagement 开启事务呢,如果不开启事务,@Transactional 是不起任何作用的。下面我们就来看看是如何开启事务的

回到顶部

TransactionAutoConfiguration

我们看到在 spring.factories 中配置了事务自动开启配置类 TransactionAutoConfiguration,我们进去看看

 1 @Configuration
 2 //和 DataSourceTransactionManagerAutoConfiguration 中是一样的
 3 //引入了 spring-boot-starter-jdbc,那自然是存在了 PlatformTransactionManager
 4 @ConditionalOnClass({PlatformTransactionManager.class})
 5 //这个自动配置类必须要在 DataSourceTransactionManagerAutoConfiguration 这个自动配置类之后才能生效
 6 //也就是前面我们已经往 Spring 容器中注入了 DataSourceTransactionManager 这个对象才执行这个配置类
 7 @AutoConfigureAfter({JtaAutoConfiguration.class, HibernateJpaAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class, Neo4jDataAutoConfiguration.class})
 8 @EnableConfigurationProperties({TransactionProperties.class})
 9 public class TransactionAutoConfiguration {
10     public TransactionAutoConfiguration() {
11     }
12 
13     @Configuration
14     @ConditionalOnBean({PlatformTransactionManager.class})
15     @ConditionalOnMissingBean({AbstractTransactionManagementConfiguration.class})
16     public static class EnableTransactionManagementConfiguration {
17         public EnableTransactionManagementConfiguration() {
18         }
19 
20         @Configuration
21         //重点:通过 @EnableTransactionManagement 注解开启事务
22         //可以看到和我们自己使用 @EnableTransactionManagement 是一样的
23         @EnableTransactionManagement(
24             proxyTargetClass = true
25         )
26         @ConditionalOnProperty(
27             prefix = "spring.aop",
28             name = {"proxy-target-class"},
29             havingValue = "true",
30             matchIfMissing = true
31         )
32         public static class CglibAutoProxyConfiguration {
33             public CglibAutoProxyConfiguration() {
34             }
35         }
36 
37         @Configuration
38         @EnableTransactionManagement(
39             proxyTargetClass = false
40         )
41         @ConditionalOnProperty(
42             prefix = "spring.aop",
43             name = {"proxy-target-class"},
44             havingValue = "false",
45             matchIfMissing = false
46         )
47         public static class JdkDynamicAutoProxyConfiguration {
48             public JdkDynamicAutoProxyConfiguration() {
49             }
50         }
51     }
52 
53     @Configuration
54     @ConditionalOnSingleCandidate(PlatformTransactionManager.class)
55     public static class TransactionTemplateConfiguration {
56         private final PlatformTransactionManager transactionManager;
57 
58         public TransactionTemplateConfiguration(PlatformTransactionManager transactionManager) {
59             this.transactionManager = transactionManager;
60         }
61 
62         @Bean
63         @ConditionalOnMissingBean
64         public TransactionTemplate transactionTemplate() {
65             return new TransactionTemplate(this.transactionManager);
66         }
67     }
68 }

我们看到 TransactionAutoConfiguration 这个自动配置类必须要在 DataSourceTransactionManagerAutoConfiguration 这个配置类之后才能生效,也就是前面我们已经往 Spring 容器中注入了 DataSourceTransactionManager 这个对象才执行这个配置类,然后通过

@EnableTransactionManagement 这个注解开启事务,其实和我们自己使用 @EnableTransactionManagement 是一样的

因此,只要我们在 SpringBoot 中引入了spring-boot-starter-jdbc这个场景启动器,就会帮我们自动开启事务了,我们只需要使用 @Transactional 就可以了

回到顶部

mybatis-spring-boot-starter

大多数时候我们在 SpringBoot 中会引入 Mybatis 这个 orm 框架,Mybaits 的场景启动器如下

<dependency>
  <groupId>org.mybatis.spring.boot</groupId>
  <artifactId>mybatis-spring-boot-starter</artifactId>
  <version>1.3.0</version>
</dependency>

我们点进去看看

我们看到 mybatis-spring-boot-starter 这个场景启动器是引入了 spring-boot-starter-jdbc 这个场景启动器的,因此只要我们在 SpringBoot 中使用 Mybaits,是自动帮我们开启了 Spring 事务的

回到顶部

总结

springboot 开启事物很简单,只需要加一行注解@Transactional就可以了,前提你用的是 jdbctemplate, jpa, Mybatis,这种常见的 orm。