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); }
总结
至此实现了多数据源的动态切换。可以在同一个方法里面进行操作多个数据源。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。