分布式事务一站式解决方案

1.二阶段提交

springboot分布式事务atomikos

2020年03月11日 01:42 ·  阅读 967

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

引入依赖

<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>
复制代码

修改配置文件

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自动配置

@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注解,修改配置属性即可。

@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

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

@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;
}
}
复制代码

测试

@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:"李四"}
运行测试出现异常后,两个数据库都回滚了,数据未改变

2.TCC补偿方式

 

3.最终一直性方案

posted on 2022-04-25 11:43  AnkangWenqiang  阅读(25)  评论(0编辑  收藏  举报

导航