天天看点

JTA+Atomikos解决分布式事务问题

JTA分布式事务:Java Transaction API,允许应用程序执行分布式事务处理。

Atomikos:为java平台提供增值服务并且开源的事务管理器。

基于xa协议,xa协议是以两阶段提交协议为基础的。

这种处理方案一般是针对传统架构项目的分布式事务,不适合用在微服务架构中。

下面是springboot配置多个oracle数据源,重现分布式事务问题的例子

一、添加依赖

<dependency>
            <groupId>com.oracle</groupId>
            <artifactId>ojdbc6</artifactId>
            <version>11.2.0.3</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.4</version>
        </dependency>
        <!-- 这里使用的是JPA包,也可使用JDBC包进行 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
           

由于maven仓库没有ojdbc6,需要自行下载安装

二、修改application.yml配置文件

spring:
  jpa:
    database: oracle
    show-sql: true
  datasource:
    master:
      jdbc-url: jdbc:oracle:thin:@127.0.0.1:1521:ORCL
      type: com.alibaba.druid.pool.DruidDataSource
      driver-class-name: oracle.jdbc.driver.OracleDriver
      username: wx
      password: 123
    slave1:
      jdbc-url: jdbc:oracle:thin:@127.0.0.1:1521:ORCL
      type: com.alibaba.druid.pool.DruidDataSource
      driver-class-name: oracle.jdbc.driver.OracleDriver
      username: wl
      password: 123456
           

三、创建数据源配置文件

@Configuration
public class DataSourceConfig {

    @Bean
    @Primary
    @ConfigurationProperties(prefix = "spring.datasource.master")
    public DataSource dataSource1(){
        return DataSourceBuilder.create().build();
    }

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.slave1")
    public DataSource dataSource2(){
        return DataSourceBuilder.create().build();
    }
}
           

@Primary注释表示这个数据源是默认数据源,如果没有这个注释的话,开启事务的时候会报错

四、创建JdbcTemplate配置类

@Configuration
public class JdbcTemplateConfig {

    @Bean
    public JdbcTemplate template1(@Qualifier("dataSource1")DataSource dataSource1){
        return new JdbcTemplate(dataSource1);
    }

    @Bean
    public JdbcTemplate template2(@Qualifier("dataSource2")DataSource dataSource2){
        return new JdbcTemplate(dataSource2);
    }
}
           

五、使用测试类进行测试

@RunWith(SpringRunner.class)
@SpringBootTest
public class JtaatomikosApplicationTests {
    @Autowired
    private JdbcTemplate template1;
    @Autowired
    private JdbcTemplate template2;

    @Test
    @Transactional
    public void contextLoads() {
        String sql = "INSERT INTO \"test\" VALUES('asd','张三','24')";
        template1.update(sql);
        template2.update(sql);
        int i = 1/0;
    }

}
           

test表只有三个字段:id,name,age

表里边数据都是空的。

执行测试方法contextLoads

控制台会抛异常

JTA+Atomikos解决分布式事务问题

此时去数据库查看数据会发现

JTA+Atomikos解决分布式事务问题

WL数据库插入数据成功了。

JTA+Atomikos解决分布式事务问题

WX数据库插入数据失败了。

WX数据库是主数据源,说明主数据源事务回滚成功了,但是副数据源事务没有回滚,这就是分布式事务问题。

为了解决这个问题,我们引入atomikos解决

在原来的项目基础上,添加依赖

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

修改数据源配置文件

@Configuration
public class DataSourceConfig {

    @Bean
    public DataSource dataSource1(){
        Properties properties = new Properties();
        properties.setProperty("URL","jdbc:oracle:thin:@127.0.0.1:1521:ORCL");
        properties.setProperty("user","wx");
        properties.setProperty("password","123");
        AtomikosDataSourceBean atomikosDataSourceBean = new AtomikosDataSourceBean();
        atomikosDataSourceBean.setXaProperties(properties);
        atomikosDataSourceBean.setUniqueResourceName("dataSource1");
        atomikosDataSourceBean.setXaDataSourceClassName("oracle.jdbc.xa.client.OracleXADataSource");
        return atomikosDataSourceBean;
    }

    @Bean
    public DataSource dataSource2(){
        Properties properties = new Properties();
        properties.setProperty("URL","jdbc:oracle:thin:@127.0.0.1:1521:ORCL");
        properties.setProperty("user","wl");
        properties.setProperty("password","123456");
        AtomikosDataSourceBean atomikosDataSourceBean = new AtomikosDataSourceBean();
        atomikosDataSourceBean.setXaProperties(properties);
        atomikosDataSourceBean.setUniqueResourceName("dataSource2");
        atomikosDataSourceBean.setXaDataSourceClassName("oracle.jdbc.xa.client.OracleXADataSource");
        return atomikosDataSourceBean;
    }
}
           

可以发现,我们去掉了@Primary和@ConfigurationProperties注释,手动设置数据库参数,将数据源类型改成了AtomikoDataSourceBean类型,这个类型的数据源需要添加XADataSource类型的数据源参数,这里我们添加的是OracleXADataSource,这个类就是JTA类型的。

现在我们就已经把事务交给引入进来的全局事务协调了。

执行测试方法contextLoads

可以发现控制台同样抛出/ by zero异常,WX和WL数据库都没有插入数据,说明都进行事务回滚了。

继续阅读