spring boot 2.x+mybatis-plus+多源数据库实现分布式事务
上一篇说到利用AOP通过注解方式实现多源数据库的动态切换,本篇文章为大家讲解在多数据源下实现分布式事务
在实际开发中,我们会遇到一个service中实现多个库的CRUD,但是我spring 提供的事务注解只支持单库,这时候如果我们遇到A库表插入成功,B库表插入失败,但是数据不会回滚,在A表容易产生脏数据。这种情况下就很需要分布式事务在分别处理。spring+boot的分布式事务我们利用jta来实现分布式事务
首先导入依赖
<!-- JPA -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jta-atomikos</artifactId>
</dependency>
JTA的优点就是能够支持多数据库事务同时事务管理,满足分布式系统中的数据的一致性.但是也有对应的弊端:
- 两阶段提交
- 事务时间太长,锁数据太长
- 低性能,低吞吐量
具体不懂的可以百度2PC和3PC阶段性提交
-----------------------------------------------华丽的分割线-----------------------------------------------
实现分布式事务主要实现原理是创建一个全局事务,然后由各个本地事务去阶段性提交,最后由全局事务统一提交
@Configuration
public class DataSourceConfig {
@Value("${spring.datasource.type:com.alibaba.druid.pool.xa.DruidXADataSource}")
String xaDataSourceClassName;
@Value("${mybatis-plus.mapper-locations}")
private String mapperLocations;
@Primary
@Bean(name = "sqlSessionFactory")
public SqlSessionFactory sqlSessionFactory(@Qualifier("dynamicDataSource") DataSource dataSource)
throws Exception {
MybatisSqlSessionFactoryBean bean = new MybatisSqlSessionFactoryBean();
bean.setDataSource(dataSource);
bean.setTransactionFactory(new MultiDataSourceTransactionFactory());
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
bean.setMapperLocations(resolver.getResources(mapperLocations));
return bean.getObject();
}
@Bean(name="sqlSessionTemplate")
@Primary
public SqlSessionTemplate sqlSessionTemplate(@Qualifier("sqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
return new SqlSessionTemplate(sqlSessionFactory);
}
/**
* 分布式事务使用JTA管理,只需配置一个JtaTransactionManager
* @return
*/
/*atomikos事务管理器*/
public UserTransactionManager userTransactionManager() {
UserTransactionManager userTransactionManager = new UserTransactionManager();
userTransactionManager.setForceShutdown(true);
return userTransactionManager;
}
public UserTransactionImp userTransactionImp() throws SystemException {
UserTransactionImp userTransactionImp = new UserTransactionImp();
userTransactionImp.setTransactionTimeout(5000);
return userTransactionImp;
}
@Bean
public JtaTransactionManager jtaTransactionManager() throws SystemException {
JtaTransactionManager jtaTransactionManager = new JtaTransactionManager();
jtaTransactionManager.setTransactionManager(userTransactionManager());
jtaTransactionManager.setUserTransaction(userTransactionImp());
jtaTransactionManager.setAllowCustomIsolationLevels(true);
return jtaTransactionManager;
}
最后只须在对应的实现方法上加上注解就能实现分布式事务
@Transactional(rollbackFor = Exception.class)
PS:动态数据库切换可以参考我博客的上一篇文章