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
控制台会抛异常
此时去数据库查看数据会发现
WL数据库插入数据成功了。
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数据库都没有插入数据,说明都进行事务回滚了。