SpringBoot Mybatis动态数据源切换方案实现过程
背景
最近让我做一个大数据的系统,分析了一下,麻烦的地方就是多数据源切换抽取数据。考虑到可以跨服务器跨数据库抽数,再整理数据,就配置了这个动态数据源的解决方案。在此分享给大家。
实现方案
数据库配置文件
我们项目使用的是yml形式的配置文件,采用的是hikari的数据库连接池。第一步我们自然是配置多个数据库源头。
我们找到spring的datasource,在下方配置三个数据源。
spring: application: name:dynamicDatasource datasource: test1: driver-class-name:com.mysql.jdbc.Driver url:jdbc:mysql://127.0.0.1:3306/test1?serverTimezone=GMT%2B8&characterEncoding=utf-8&useSSL=false username:root password:123456 test2: driver-class-name:com.mysql.jdbc.Driver url:jdbc:mysql://127.0.0.1:3306/test2?serverTimezone=GMT%2B8&characterEncoding=utf-8&useSSL=false username:root password:123456 test3: driver-class-name:com.mysql.jdbc.Driver url:jdbc:mysql://127.0.0.1:3306/test3?serverTimezone=GMT%2B8&characterEncoding=utf-8&useSSL=false username:root password:123456 hikari: leak-detection-threshold:2000
定义数据源实体类
我们可以建立个datasourceBean文件夹专门管理数据源的实体类。
我们这里要建立三个实体类。分别对应test1,test2,test3
@Configuration
publicclassTest1DataSourceBean{
@Value("${spring.datasource.test1.driver-class-name}")
privateStringtest1Driver;
@Value("${spring.datasource.test1.url}")
privateStringtest1Url;
@Value("${spring.datasource.test1.username}")
privateStringtest1Username;
@Value("${spring.datasource.test1.password}")
privateStringtest1Password;
@Bean(name="test1DataSource")
publicDataSourcetest1DataSource()throwsException{
HikariDataSourcedataSource=newHikariDataSource();
dataSource.setDriverClassName(test1Driver);
dataSource.setJdbcUrl(test1Url);
dataSource.setUsername(test1Username);
dataSource.setPassword(test1Password);
returndataSource;
}
}
@Configuration
publicclassTest2DataSourceBean{
@Value("${spring.datasource.test2.driver-class-name}")
privateStringtest2Driver;
@Value("${spring.datasource.test2.url}")
privateStringtest2Url;
@Value("${spring.datasource.test2.username}")
privateStringtest2Username;
@Value("${spring.datasource.test2.password}")
privateStringtest2Password;
@Bean(name="test2DataSource")
publicDataSourcetest2DataSource()throwsException{
HikariDataSourcedataSource=newHikariDataSource();
dataSource.setDriverClassName(test2Driver);
dataSource.setJdbcUrl(test2Url);
dataSource.setUsername(test2Username);
dataSource.setPassword(test2Password);
returndataSource;
}
}
@Configuration
publicclassTest3DataSourceBean{
@Value("${spring.datasource.test3.driver-class-name}")
privateStringtest3Driver;
@Value("${spring.datasource.test3.url}")
privateStringtest3Url;
@Value("${spring.datasource.test3.username}")
privateStringtest3Username;
@Value("${spring.datasource.test3.password}")
privateStringtest3Password;
@Bean(name="test3DataSource")
publicDataSourcetest3DataSource()throwsException{
HikariDataSourcedataSource=newHikariDataSource();
dataSource.setDriverClassName(test3Driver);
dataSource.setJdbcUrl(test3Url);
dataSource.setUsername(test3Username);
dataSource.setPassword(test3Password);
returndataSource;
}
}
定义一个枚举类管理数据源
publicenumDatabaseType{
test1("test1","test1"),
test2("test2","test2"),
test3("test3","test3");
privateStringname;
privateStringvalue;
DatabaseType(Stringname,Stringvalue){
this.name=name;
this.value=value;
}
publicStringgetName(){
returnname;
}
publicStringgetValue(){
returnvalue;
}
}
定义一个线程安全的数据源容器
publicclassDatabaseContextHolder{
privatestaticfinalThreadLocalcontextHolder=newThreadLocal<>();
publicstaticvoidsetDatabaseType(DatabaseTypetype){
contextHolder.set(type);
}
publicstaticDatabaseTypegetDatabaseType(){
returncontextHolder.get();
}
}
定义动态数据源
publicclassDynamicDataSourceextendsAbstractRoutingDataSource{
protectedObjectdetermineCurrentLookupKey(){
returnDatabaseContextHolder.getDatabaseType();
}
}
mybatis配置类
网上的很多文章配置出来都会产生数据源循环依赖的问题,这里解决了这个问题。
@Configuration
@MapperScan(basePackages="cn.test.jichi",sqlSessionFactoryRef="sessionFactory")
publicclassMybatisConfig{
/**
*@Description:设置动态数据源
*/
@Bean(name="dynamicDataSource")
@Primary
publicDynamicDataSourceDataSource(
@Qualifier("test1DataSource")DataSourcetest1DataSource,
@Qualifier("test2DataSource")DataSourcetest2DataSource,
@Qualifier("test3DataSource")DataSourcetest3DataSource){
Map
示例
publicvoidtestDymnaicDatasource(){
//不切换数据源默认是自己的。
System.out.println("-----默认数据源");
DemoEntitytotalCount=demoMapper.getTotalCount();
StringnameCount1=totalCount.getNameCount();
StringageCount2=totalCount.getAgeCount();
System.out.println("nameCount:"+nameCount1);
System.out.println("ageCount:"+ageCount2);
//数据源切换为branch
System.out.println("-----数据源为test2");
DynamicDataSourceUtils.chooseBranchDataSource();
IntegernameCount=demoMapper.getNameCount();
IntegerageCount=demoMapper.getAgeCount();
System.out.println("nameCount:"+nameCount);
System.out.println("ageCount:"+ageCount);
//数据源为basic
System.out.println("-----数据源为test3");
DynamicDataSourceUtils.chooseBasicDataSource();
IntegerageCount1=demoMapper.getAgeCount();
System.out.println("ageCount:"+ageCount1);
}
总结
至此实现了多数据源的动态切换。可以在同一个方法里面进行操作多个数据源。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。