zoukankan      html  css  js  c++  java
  • 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
        public DataSource dataSource() {
            ComboPooledDataSource dataSource = new ComboPooledDataSource();
            dataSource.setUser("...");
            dataSource.setPassword("...");
            dataSource.setDriverClass("...");
            dataSource.setJdbcUrl("...");
            return dataSource;
        }
      
        //重要
        @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。

  • 相关阅读:
    能成大事儿的人,都具备这5个特质
    元气森林唐彬森:苦了10年我发现,发大财首先要会选
    反者道之动,亿万富翁查理芒格受用一生的逆向思维
    解决不了bug先放着,这里有40条提升编程技能小妙招
    理解maven命令package、install、deploy的联系与区别
    每日一则
    《穷查理年鉴》贪嗔痴 & 懒贪装(关于败坏)
    C++构造函数
    C++类的定义和封装
    C++访问控制限定符
  • 原文地址:https://www.cnblogs.com/java-chen-hao/p/11844523.html
Copyright © 2011-2022 走看看