Spring Boot2.0之多数据源分布式事务问题详解编程语言

分布式事务解决方案的问题,

分布式事务产生的原因:

  多个不同的服务连接不同的数据源 ,做分布式事务的管理。

 Spring Boot2.0之多数据源分布式事务问题详解编程语言

这种情况是连接两个数据源的情况,然后事务管理器是这样的 只管理了test02的这端业务代码。所以test02的这个会回滚!

但是test01会入库哦

这属于传统的分布式事务解决方案

   使用springboot+jta+atomikos 分布式事物管理 (不适合微服务,需要拿到数据源然后注册到同一个全局事务里面去)

好了废话不多说,动手撸代码!

引入的jar:

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

配置文件也要修改:

application.properties:

# Mysql 1 
mysql.datasource.test1.url = jdbc:mysql://localhost:3306/test01?useUnicode=true&characterEncoding=utf-8 
mysql.datasource.test1.username = root 
mysql.datasource.test1.password = root 
 
mysql.datasource.test1.minPoolSize = 3 
mysql.datasource.test1.maxPoolSize = 25 
mysql.datasource.test1.maxLifetime = 20000 
mysql.datasource.test1.borrowConnectionTimeout = 30 
mysql.datasource.test1.loginTimeout = 30 
mysql.datasource.test1.maintenanceInterval = 60 
mysql.datasource.test1.maxIdleTime = 60 
 
 
 
# Mysql 2 
mysql.datasource.test2.url =jdbc:mysql://localhost:3306/test02?useUnicode=true&characterEncoding=utf-8 
mysql.datasource.test2.username =root 
mysql.datasource.test2.password =root 
 
mysql.datasource.test2.minPoolSize = 3 
mysql.datasource.test2.maxPoolSize = 25 
mysql.datasource.test2.maxLifetime = 20000 
mysql.datasource.test2.borrowConnectionTimeout = 30 
mysql.datasource.test2.loginTimeout = 30 
mysql.datasource.test2.maintenanceInterval = 60 
mysql.datasource.test2.maxIdleTime = 60 

 然后创建包:com.toov5.configure

 

 

 

Spring Boot2.0之多数据源分布式事务问题详解编程语言

 

 底层原理是使用的2PC

 

package com.toov5.configure; 
 
import org.springframework.boot.context.properties.ConfigurationProperties; 
 
import lombok.Data; 
 
@Data 
@ConfigurationProperties(prefix = "mysql.datasource.test1") 
public class DBConfig1 { 
 
    private String url; 
    private String username; 
    private String password; 
    private int minPoolSize; 
    private int maxPoolSize; 
    private int maxLifetime; 
    private int borrowConnectionTimeout; 
    private int loginTimeout; 
    private int maintenanceInterval; 
    private int maxIdleTime; 
    private String testQuery; 
}
package com.toov5.configure; 
 
import org.springframework.boot.context.properties.ConfigurationProperties; 
 
import lombok.Data; 
//读取解析配置文件,获取值 
@Data 
@ConfigurationProperties(prefix = "mysql.datasource.test2") 
public class DBConfig2 { 
 
    private String url; 
    private String username; 
    private String password; 
    private int minPoolSize; 
    private int maxPoolSize; 
    private int maxLifetime; 
    private int borrowConnectionTimeout; 
    private int loginTimeout; 
    private int maintenanceInterval; 
    private int maxIdleTime; 
    private String testQuery; 
}

datasource包下面:

package com.toov5.datasource; 
 
import java.sql.SQLException; 
 
import javax.sql.DataSource; 
 
import org.apache.ibatis.session.SqlSessionFactory; 
import org.mybatis.spring.SqlSessionFactoryBean; 
import org.mybatis.spring.SqlSessionTemplate; 
import org.mybatis.spring.annotation.MapperScan; 
import org.springframework.beans.factory.annotation.Qualifier; 
import org.springframework.context.annotation.Bean; 
import org.springframework.context.annotation.Configuration;  
 
import com.atomikos.jdbc.AtomikosDataSourceBean; 
import com.mysql.jdbc.jdbc2.optional.MysqlXADataSource; 
import com.toov5.configure.DBConfig1; 
 
@Configuration 
// basePackages 最好分开配置 如果放在同一个文件夹可能会报错 
//跟之前都一样。扫包然后指定工厂 
//没有配置事务管理器,相当于将本地事务注册到Atomikos全局事务 
@MapperScan(basePackages = "com.toov5.test01", sqlSessionTemplateRef = "testSqlSessionTemplate") 
public class MyBatisConfig1 { 
 
    // 配置数据源 
     
    @Bean(name = "testDataSource") 
    public DataSource testDataSource(DBConfig1 testConfig) throws SQLException { 
        MysqlXADataSource mysqlXaDataSource = new MysqlXADataSource(); 
        mysqlXaDataSource.setUrl(testConfig.getUrl()); 
        mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true); 
        mysqlXaDataSource.setPassword(testConfig.getPassword()); 
        mysqlXaDataSource.setUser(testConfig.getUsername()); 
        mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true); 
  
         
        //创建Atomikos全局事务,所有的事务注册进来 
        AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean(); 
        xaDataSource.setXaDataSource(mysqlXaDataSource); 
        xaDataSource.setUniqueResourceName("testDataSource"); //testDataSource这个数据源的注册 
 
        xaDataSource.setMinPoolSize(testConfig.getMinPoolSize()); 
        xaDataSource.setMaxPoolSize(testConfig.getMaxPoolSize()); 
        xaDataSource.setMaxLifetime(testConfig.getMaxLifetime()); 
        xaDataSource.setBorrowConnectionTimeout(testConfig.getBorrowConnectionTimeout()); 
        xaDataSource.setLoginTimeout(testConfig.getLoginTimeout()); 
        xaDataSource.setMaintenanceInterval(testConfig.getMaintenanceInterval()); 
        xaDataSource.setMaxIdleTime(testConfig.getMaxIdleTime()); 
        xaDataSource.setTestQuery(testConfig.getTestQuery()); 
        return xaDataSource; 
    } 
 
     
    @Bean(name = "testSqlSessionFactory") 
    public SqlSessionFactory testSqlSessionFactory(@Qualifier("testDataSource") DataSource dataSource) 
            throws Exception { 
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean(); 
        bean.setDataSource(dataSource); 
        return bean.getObject(); 
    } 
 
     
    @Bean(name = "testSqlSessionTemplate") 
    public SqlSessionTemplate testSqlSessionTemplate( 
            @Qualifier("testSqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception { 
        return new SqlSessionTemplate(sqlSessionFactory); 
    } 
}
package com.toov5.datasource; 
 
import java.sql.SQLException; 
 
import javax.sql.DataSource; 
 
import org.apache.ibatis.session.SqlSessionFactory; 
import org.mybatis.spring.SqlSessionFactoryBean; 
import org.mybatis.spring.SqlSessionTemplate; 
import org.mybatis.spring.annotation.MapperScan; 
import org.springframework.beans.factory.annotation.Qualifier; 
import org.springframework.context.annotation.Bean; 
import org.springframework.context.annotation.Configuration; 
 
import com.atomikos.jdbc.AtomikosDataSourceBean; 
import com.mysql.jdbc.jdbc2.optional.MysqlXADataSource; 
import com.toov5.configure.DBConfig2; 
 
@Configuration 
@MapperScan(basePackages = "com.toov5.test02", sqlSessionTemplateRef = "test2SqlSessionTemplate") 
public class MyBatisConfig2 { 
 
    // 配置数据源 
    @Bean(name = "test2DataSource") 
    public DataSource testDataSource(DBConfig2 testConfig) throws SQLException { 
        MysqlXADataSource mysqlXaDataSource = new MysqlXADataSource(); 
        mysqlXaDataSource.setUrl(testConfig.getUrl()); 
        mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true); 
        mysqlXaDataSource.setPassword(testConfig.getPassword()); 
        mysqlXaDataSource.setUser(testConfig.getUsername()); 
        mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true); 
 
        AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean(); 
        xaDataSource.setXaDataSource(mysqlXaDataSource); 
        xaDataSource.setUniqueResourceName("test2DataSource"); 
 
        xaDataSource.setMinPoolSize(testConfig.getMinPoolSize()); 
        xaDataSource.setMaxPoolSize(testConfig.getMaxPoolSize()); 
        xaDataSource.setMaxLifetime(testConfig.getMaxLifetime()); 
        xaDataSource.setBorrowConnectionTimeout(testConfig.getBorrowConnectionTimeout()); 
        xaDataSource.setLoginTimeout(testConfig.getLoginTimeout()); 
        xaDataSource.setMaintenanceInterval(testConfig.getMaintenanceInterval()); 
        xaDataSource.setMaxIdleTime(testConfig.getMaxIdleTime()); 
        xaDataSource.setTestQuery(testConfig.getTestQuery()); 
        return xaDataSource; 
    } 
 
    @Bean(name = "test2SqlSessionFactory") 
    public SqlSessionFactory testSqlSessionFactory(@Qualifier("test2DataSource") DataSource dataSource) 
            throws Exception { 
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean(); 
        bean.setDataSource(dataSource); 
        return bean.getObject(); 
    } 
 
    @Bean(name = "test2SqlSessionTemplate") 
    public SqlSessionTemplate testSqlSessionTemplate( 
            @Qualifier("test2SqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception { 
        return new SqlSessionTemplate(sqlSessionFactory); 
    } 
}

 

 

 service中的事务管理不需要去写了!

package com.toov5.test02.service02; 
 
import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.stereotype.Service; 
import org.springframework.transaction.annotation.Transactional; 
 
import com.toov5.test01.mappertest01.UserMapperTest01; 
import com.toov5.test02.mappertest02.UserMapperTest02; 
 
import lombok.extern.slf4j.Slf4j; 
 
@Service 
@Slf4j 
public class UserService02 { 
  @Autowired 
  private UserMapperTest01 userMapperTest01; 
  @Autowired 
  private UserMapperTest02 userMapperTest02; 
  
   
  @Transactionalpublic int test01Andtest02(String name, Integer age){ 
        //连接两个数据源 
          int result1 = userMapperTest01.insert(name, age); 
          int result2 = userMapperTest02.insert(name, age); 
          int i = 1/0; 
          int result = result1+result2; 
          return result; 
      } 
   
}

 

目录结构:

Spring Boot2.0之多数据源分布式事务问题详解编程语言

项目启动类

package com.toov5.app; 
 
import org.springframework.boot.SpringApplication; 
import org.springframework.boot.autoconfigure.SpringBootApplication; 
import org.springframework.boot.context.properties.EnableConfigurationProperties; 
 
import com.toov5.configure.DBConfig1; 
import com.toov5.configure.DBConfig2; @SpringBootApplication(scanBasePackages={"com.toov5.*"}) @EnableConfigurationProperties(value = { DBConfig1.class, DBConfig2.class }) //开启读取配置文件,启动时候去读取配置文件 public class app { public static void main(String[] args) { SpringApplication.run(app.class, args); } }

 

 ok,到此为止。是不是很简单呀~

 

原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/16162.html

(0)
上一篇 2021年7月19日
下一篇 2021年7月19日

相关推荐

发表回复

登录后才能评论