转载

SpringBoot整合JTA

  • JTA,即Java Transaction API,JTA允许应用程序执行分布式事务处理——在两个或多个网络计算机资源上访问并且更新数据。JDBC驱动程序的JTA支持极大地增强了数据访问能力。
  • JTA是基于XA标准制定的,采用两阶段提交的方式来管理分布式事务。即是一个事务管理器和多个资源管理器协作完成,第一阶段各个资源管理器提交,第二个阶段事务管理器需要查看资源管理器是否全部提交成功再提交。
  • Java实现JTA强一致性的事务有很多种实现,笔者只是选择了atomikos的实现

SpringBoot整合

  • 添加依赖
<dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-jta-atomikos</artifactId>
      </dependency>
  • 准备两个数据源,笔者是和Mybatis整合的,因此需要将数据源和Mybatis单独绑定,如下:
/**
 * @Description 数据源的配置
 * @Author CJB
 * @Date 2020/3/9 13:45
 */
@Configuration
public class DatasourceConfig{

    /**
     * 第一个数据源的配置
     */
    @Configuration
    public static class DataSourceConfig1{
        /**
         * 注入DruidXADataSource,Druid对JTA的支持,支持XA协议,采用两阶段事务的提交
         * @return
         */
        @ConfigurationProperties(prefix = "spring.datasource1")
        @Bean(value = "druidXADataSource1")
        public DruidXADataSource druidXADataSource1(){
            return new DruidXADataSource();
        }

        @Bean(name = "dataSource1")
        public DataSource dataSource1(@Qualifier("druidXADataSource1")DruidXADataSource dataSource){
            AtomikosDataSourceBean xaDataSource=new AtomikosDataSourceBean();
            xaDataSource.setXaDataSource(dataSource);
            xaDataSource.setUniqueResourceName("dataSource1");
            return xaDataSource;
        }

        /**
         * Mybatis对多数据源的整合
         * @param dataSource
         * @return
         * @throws Exception
         */
        @Bean(name = "sqlSessionFactory1")
        public SqlSessionFactory sqlSessionFactory1(@Qualifier(value ="dataSource1")DataSource dataSource)throws Exception {
            SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
            factory.setDataSource(dataSource);
            factory.setVfs(SpringBootVFS.class);
            org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
            configuration.setMapUnderscoreToCamelCase(true);
            factory.setConfiguration(configuration);
            factory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:/mapper1/**/*.xml"));
            return factory.getObject();
        }

        @Bean(name = "sqlSessionTemplate1")
        public SqlSessionTemplate sqlSessionTemplate(@Qualifier("sqlSessionFactory1")SqlSessionFactory sqlSessionFactory){
            return new SqlSessionTemplate(sqlSessionFactory);
        }

        /**
         * 配置mapper文件的扫描,注入mapper,也可以使用@MapperScan注解扫描,其中有一个属性指定sqlSessionFactory
         */
        @Bean(value = "mapperScannerConfigurer1")
        public MapperScannerConfigurer mapperScannerConfigurer(){
            MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
            // 设置sqlSessionFactory名
            mapperScannerConfigurer.setSqlSessionFactoryBeanName("sqlSessionFactory1");
            // 设置接口映射器基础包名
            mapperScannerConfigurer.setBasePackage("com.vivachek.service.dao");
            return mapperScannerConfigurer;
        }
    }


    /**
     * 第二个数据源的配置
     */
    @Configuration
    public static class DataSourceConfig2{

        @ConfigurationProperties(prefix = "spring.datasource2")
        @Bean(value = "druidXADataSource2")
        public DruidXADataSource druidXADataSource2(){
            return new DruidXADataSource();
        }

        @Bean(name = "dataSource2")
        public DataSource dataSource2(@Qualifier("druidXADataSource2")DruidXADataSource dataSource){
            AtomikosDataSourceBean xaDataSource=new AtomikosDataSourceBean();
            xaDataSource.setXaDataSource(dataSource);
            xaDataSource.setUniqueResourceName("dataSource2");
            return xaDataSource;
        }

        //配置Mybatis
        @Bean(name = "sqlSessionFactory2")
        public SqlSessionFactory sqlSessionFactory1(@Qualifier(value ="dataSource2")DataSource dataSource)throws Exception {
            SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
            factory.setDataSource(dataSource);
            factory.setVfs(SpringBootVFS.class);
            org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
            configuration.setMapUnderscoreToCamelCase(true);
            factory.setConfiguration(configuration);
            factory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:/mapper2/**/*.xml"));
            return factory.getObject();
        }

        @Bean(name = "sqlSessionTemplate2")
        public SqlSessionTemplate sqlSessionTemplate(@Qualifier("sqlSessionFactory2")SqlSessionFactory sqlSessionFactory){
            return new SqlSessionTemplate(sqlSessionFactory);
        }

        //配置Mapper扫描器,整合mybatis的时候多数据源必须配置
        @Bean(value = "mapperScannerConfigurer2")
        public MapperScannerConfigurer mapperScannerConfigurer(){
            MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
            // 设置sqlSessionFactory名
            mapperScannerConfigurer.setSqlSessionFactoryBeanName("sqlSessionFactory2");
            // 设置接口映射器基础包名
            mapperScannerConfigurer.setBasePackage("com.vivachek.service.dao2");
            return mapperScannerConfigurer;
        }
    }
@Transactional

注意

  • 使用 MapperScan 注解直接注入Mapper的时候需要使用 sqlSessionFactoryRef 属性指定对应的SqlSessionFactory。当然笔者采用的配置的方式。
  • 关于实现的原理这里不再细说了,读者自己读读源码就能很清楚的知晓了,SpringBoot源码万变不离自动配置类,设计到的配置类如下:
    • TransactionAutoConfiguration :事务的自动配置类
    • DataSourceTransactionManagerAutoConfiguratio :数据源事务管理器的自动配置类
    • AtomikosJtaConfiguratioJndiJtaConfiguration :JTA事务的自动配置类
  • 关于事务的执行原理可以看看笔者之前的文章,Spring事务源码解析
原文  https://chenjiabing666.github.io/2020/03/11/SpringBoot整合JTA/
正文到此结束
Loading...