springboot分布式事务atomikos

atomikos应用场景:单应用多数据源

引入依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
复制代码<dependency>  
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jta-atomikos</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.0.1</version>
</dependency>
<!-- 这里不使用自动配置,所以不引入starter -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.14</version>
</dependency>

<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>

<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>

修改配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
复制代码spring:  
datasource:
#使用druid连接池
druid:
#数据源1的名称
one:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://192.168.211.128:3306/test?useUnicode=true&characterEncoding=UTF-8&useSSL=false
username: root
password: root
#数据源2的名称
two:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://192.168.211.129:3306/test?useUnicode=true&characterEncoding=UTF-8&useSSL=false
username: root
password: root

配置数据源

只需要配置数据源即可,全局事务管理器(JtaTransactionManager)由spring自动配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
复制代码@Configuration  
public class DataSourceConfig {

/**
* 创建Druid的XA连接池
* @return
*/
@Bean
@ConfigurationProperties("spring.datasource.druid.one")
public XADataSource druidXADataSource1(){
return new DruidXADataSource();
}

/**
* 创建Atomikos数据源
* 注解@DependsOn("druidXADataSource1"),在名为druidXADataSource1的bean实例化后加载当前bean
* @param xaDataSource
* @return
*/
@Bean
@DependsOn("druidXADataSource1")
@Primary
public DataSource dataSource1(@Qualifier("druidXADataSource1") XADataSource xaDataSource) {
//这里的AtomikosDataSourceBean使用的是spring提供的
AtomikosDataSourceBean dataSource = new AtomikosDataSourceBean();
dataSource.setXaDataSource(xaDataSource);
return dataSource;
}


@Bean
@ConfigurationProperties("spring.datasource.druid.two")
public XADataSource druidXADataSource2(){
return new DruidXADataSource();
}

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

配置mybatis

如果使用其他的orm框架,自行配置。

数据源2的mybatis配置和下面代码相似,去除@Primary注解,修改配置属性即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
复制代码@Configuration  
//指定扫描的dao包和SqlSession实例
@MapperScan(basePackages = "demo.springboot.atomikos.dao1", sqlSessionTemplateRef = "sessionTemplate1")
public class Mybatis1Config {

/**
* SqlSessionFactory
*
* @param dataSource
* @return
* @throws Exception
*/
@Bean
@Primary
public SqlSessionFactory sqlSessionFactory1(@Qualifier("dataSource1") DataSource dataSource) throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
//mapper文件位置
// bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/one/*.xml"));
return bean.getObject();
}

/**
* SqlSession实例
*
* @param sqlSessionFactory
* @return
*/
@Bean
@Primary
public SqlSessionTemplate sessionTemplate1(@Qualifier("sqlSessionFactory1") SqlSessionFactory sqlSessionFactory) {
return new SqlSessionTemplate(sqlSessionFactory);
}
}

DAO

1
2
3
4
5
6
7
8
9
10
11
复制代码public interface UserDAO1 {  

@Update("update user set name = #{name} where id = #{id}")
int updateById(@Param("name")String name, @Param("id")Long id);
}

public interface UserDAO2 {

@Update("update user set name = #{name} where id = #{id}")
int updateById(@Param("name")String name, @Param("id")Long id);
}

service

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
复制代码@Service  
public class TestService {
@Autowired
private UserDAO1 userDAO1;
@Autowired
private UserDAO2 userDAO2;

/**
* 在需要事务的方法加上@Transactional注解即可
*/
@Transactional
public void test(){
userDAO1.updateById("haha", 1L);
userDAO2.updateById("hehe", 2L);
//模拟异常
int a = 1/0;
}
}

测试

1
2
3
4
5
6
7
8
9
10
11
12
13
复制代码@RunWith(SpringRunner.class)  
@SpringBootTest
public class AtomikosApplicationTests {

@Autowired
private TestService testService;

@Test
public void test() {
testService.test();
}

}

数据源1中的User{“id”:1,”name”:”张三”}

数据源2中的User{“id”:2,name:”李四”}

运行测试出现异常后,两个数据库都回滚了,数据未改变

项目路径


作者博客

作者公众号
在这里插入图片描述

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%