mysql多数据源事务_MybatisPlus多数据源及事务解决思路关于多数据源解决⽅案
⽬前在SpringBoot框架基础上多数据源的解决⽅案⼤多⼿动创建多个DataSource,后续⽅案有三:
继承org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource,使⽤AOP切⾯注⼊相应的数据源 ,但是这种做法仅仅适⽤单Service⽅法使⽤⼀个数据源可⾏,如果单Service⽅法有多个数据源执⾏会造成误读。
通过DataSource配置 JdbcTemplateBean,直接使⽤ JdbcTemplate操控数据源。
分别通过DataSource创建SqlSessionFactory并扫描相应的Mapper⽂件和Mapper接⼝。
MybatisPlus的多数据源
我通过阅读源码,发现MybatisPlus的多数据源解决⽅案正是AOP,继承了
org.springframework.jdbc.datasource.AbstractDataSource,有⾃⼰对ThreadLocal的处理。通过注解切换数据源。也就是
说,MybatisPlus只⽀持在单Service⽅法内操作⼀个数据源,毕竟官⽹都指明——“强烈建议只注解在service实现上”。
⽽后,注意看com.baomidou.lkit.DynamicDataSourceContextHolder,也就是MybatisPlus是如何切换数据源的。
重点看:
/**
* 为什么要⽤链表存储(准确的是栈)jdbctemplate查询一条数据
*
* 为了⽀持嵌套切换,如ABC三个service都是不同的数据源
* 其中A的某个业务要调B的⽅法,B的⽅法需要调⽤C的⽅法。⼀级⼀级调⽤切换,形成了链。
* 传统的只设置当前线程的⽅式不能满⾜此业务需求,必须模拟栈,后进先出。
*
*/
private static final ThreadLocal> LOOKUP_KEY_HOLDER = new ThreadLocal() {
@Override
protected Object initialValue() {
return new ArrayDeque();
}
};
这段话翻译为⼤家都能懂得的意思就是**“可以同时操控多个数据源”**。那么,在MYSQL中,有语法为schemaName+. +tableName,如此⼀来就不会误⾛数据源了。
我继续看MybatisPlus是如何利⽤mybatis本⾝的ORM机制将实体类⾃动映射以及⽣成SQL语句的(这⾥插⼀句,MybatisPlus的源码易读懂,写的很不错)。⽆意看到了注解batisplus.annotation.TableName中的schema,如果在类上加schema,在⽣成SQL语句时就会⽣成schemaName+. +tableName格式。
MybatisPlus多数据源事务(JTA)
简单说明⼀下JTA
JTA包括事务管理器(Transaction Manager)和⼀个或多个⽀持 XA 协议的资源管理器 ( Resource Manager ) 两部分, 可以将资源管理器看做任意类型的持久化数据存储;事务管理器则承担着所有事务参与单元的协调与控制。
JTA只是提供了⼀个接⼝,并没有提供具体的实现。
不过Atomikos对其进⾏了实现,⽽后SpringBoot将其进⾏了整合,对其进⾏了托管,很⽅便开发者拿来即⽤。
其中事务管理器的主要部分为UserTransaction 接⼝,开发⼈员通过此接⼝在信息系统中实现分布式事务;⽽资源管理器则⽤来规范提供商(如数据库连接提供商)所提供的事务服务,它约定了事务的资源管
理功能,使得 JTA 可以在异构事务资源之间执⾏协同沟通。
通常接⼊JTA步骤(⽬的就是让JTA的UserTransaction接管驱动为分布式的数据源,通常为AtomikosDataSourceBean):
配置好AtomikosDataSourceBean。
把AtomikosDataSourceBean交给SqlSessionFactory。
配置UserTransaction事务管理。
但是我们⽤的是MybatisPlus,我们需要做的是接管MybatisPlus每⼀个数据源的配置,然后再把数据源依次交给MybatisPlus进⾏管理。
看看MybatisPlus是怎么进⾏多数据源配置的,源码⾥有这⼏个地⽅需要重点看⼀下:
com.baomidou.dynamic.datasource.provider.AbstractDataSourceProvider,这个就是MybatisPlus多数据源配置的⽅式,利⽤HashMap来装载。
com.baomidou.dynamic.datasource.DynamicDataSourceCreator,这个是每个数据源的配置⽅式。
其中com.baomidou.dynamic.datasource.provider.AbstractDataSourceProvider实现了接⼝
com.baomidou.dynamic.datasource.provider.DynamicDataSourceProvider,是该接⼝的默认的实现。也就是说我们只需要实现该接⼝,⾃⼰配置多数据源以及每个数据源的驱动,成为该接⼝的默认实现就OK。
实现该接⼝,配置多数据源: x.config;
import com.baomidou.dynamic.datasource.provider.DynamicDataSourceProvider;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties;
import t.annotation.Primary;
import org.springframework.stereotype.Service;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
/**
* @author : zuoyu
* @description : 接管MybatisPlus多数据源⾄Atomikos管理
* @date : 2020-06-01 16:36
**/
@Service
@Primary
public class DynamicDataSourceProviderImpl implements DynamicDataSourceProvider {
/**
* 配置⽂件数据的松散绑定
*/
private final DynamicDataSourceProperties properties;
/**
* Atomikos驱动数据源创建
*/
private final AtomikosDataSourceCreator atomikosDataSourceCreator;
public DynamicDataSourceProviderImpl(DynamicDataSourceProperties properties, AtomikosDataSourceCreator atomikosDataSourceCreator) {
this.properties = properties;
this.atomikosDataSourceCreator = atomikosDataSourceCreator;
}
@Override
public Map loadDataSources() {
Map dataSourcePropertiesMap = Datasource();
Map dataSourceMap = new HashMap<>(dataSourcePropertiesMap.size() * 2);
for (Map.Entry item : Set()) {
String pollName = Key();
DataSourceProperty dataSourceProperty = Value();
dataSourceProperty.setPollName(pollName);
dataSourceMap.put(pollName, ateDataSource(dataSourceProperty));
}
return dataSourceMap;
}
}
Atomikos驱动数据源创建: x.config;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty;
sql.jdbc.jdbc2.optional.MysqlXADataSource;
import org.springframework.boot.jta.atomikos.AtomikosDataSourceBean;
import org.springframework.stereotype.Component;
import javax.sql.DataSource;
/**
* @author : zuoyu
* @description : 事务数据源
* @date : 2020-06-01 17:30
**/
@Component
public class AtomikosDataSourceCreator {
/**
* 创建数据源
*
* @param dataSourceProperty 数据源信息
* @return 数据源
*/
public DataSource createDataSource(DataSourceProperty dataSourceProperty) { MysqlXADataSource mysqlXaDataSource = new MysqlXADataSource(); mysqlXaDataSource.Url());
mysqlXaDataSource.Password()); mysqlXaDataSource.Username()); AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean(); xaDataSource.setXaDataSource(mysqlXaDataSource);
xaDataSource.setMinPoolSize(5);
xaDataSource.setBorrowConnectionTimeout(60);
xaDataSource.setMaxPoolSize(20);
xaDataSource.DriverClassName()); xaDataSource.setTestQuery("SELECT 1 FROM DUAL");
xaDataSource.PollName());
return xaDataSource;
}
}
配置JTA事务管理器: x.config;
import com.atomikos.icatch.jta.UserTransactionImp;
import com.atomikos.icatch.jta.UserTransactionManager;
import t.annotation.Bean;
import t.annotation.Configuration;
import t.annotation.DependsOn;
import ansaction.PlatformTransactionManager;
import ansaction.annotation.EnableTransactionManagement; import ansaction.jta.JtaTransactionManager;
ansaction.TransactionManager;
ansaction.UserTransaction;
/**
* @author : zuoyu
* @description : 分布式事务配置
* @date : 2020-06-01 17:55
**/
@Configuration
@EnableTransactionManagement
public class TransactionManagerConfig {
@Bean(name = "userTransaction")
public UserTransaction userTransaction() throws Throwable {
UserTransactionImp userTransactionImp = new UserTransactionImp(); userTransactionImp.setTransactionTimeout(10000);
return userTransactionImp;
}
@Bean(name = "atomikosTransactionManager")
public TransactionManager atomikosTransactionManager() throws Throwable { UserTransactionManager userTransactionManager = new UserTransactionManager(); userTransactionManager.setForceShutdown(false);
return userTransactionManager;
}
@Bean(name = "transactionManager")
@DependsOn({"userTransaction", "atomikosTransactionManager"})
public PlatformTransactionManager transactionManager() throws Throwable {
return new JtaTransactionManager(userTransaction(), atomikosTransactionManager()); }

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。