DynamicDataSource 动态数据源
需求:
数仓项目需要大致检验数据同步的正确性,有多台MySQL业务数据库,一台数据仓库Postgres。需要检验MySQL各个库中表的条数与postgres中表的条数是否一致。
问题:
Mybatis+MySQL操作每个数据库,需要配置每个数据库的数据源,如配置 url:jdbc://mysql:localhost:8081/user 。
Postgres则没有此烦恼,所有表均在一个库中。 只需要配置一次数据源。
但是MySQL业务数据存储到不同服务器上,且每台数据库服务器上有数十个库。如果使用常规的Springboot + mybatis,通过application.yml来配置数据源,显然不切实际。因此,也考虑过使用原生的jdbc来操纵数据库,但是频繁创建数据源和连接数据库存在性能问题。
解决方案:
使用动态DynamicDataSource ,将数据源信息存储至Postgres中一个映射表,通过读取映射来配置数据源。最后,通过key的值来切换数据源,实现数据增删改查。
实现过程
pom.xml
<!-- postgres-->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>${postgresql.version}</version>
</dependency>
<!-- mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
<version>8.0.13</version>
</dependency>
<!-- mybatis -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${starter.mybatis.spring.version}</version>
</dependency>
<!-- DynamicDataSource -->
<dependency>
<groupId>com.github.yeecode.dynamicdatasource</groupId>
<artifactId>DynamicDataSource</artifactId>
<version>1.3.0</version>
</dependency>
配置applicaiton.yml设置默认数据源
dynamicDataSource:
default:
url: jdbc:postgresql://localhost:5432/postgres
driverClassName: org.postgresql.Driver
username:
password:
配置spirngboot启动器
1.去除自动配置数据源
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
2.扫描包
@ComponentScan(basePackages = {"com.github.yeecode.dynamicdatasource","业务包"})
新增数据源
public void addDynamicDataSource(List<CheckResult> checkResultList) {
String pgDriverClass = "org.postgresql.Driver";
String pgUrl = "jdbc:postgresql://localhost:5432/postgres";
String pgUserName = "";
String pgPassword = "";
List<DataSourceInfo> allDataSource = getAllDataSource(checkResultList);
if (CollectionUtils.isEmpty(allDataSource)) {
return;
}
//----------------------- Mysql 数据源 ---------------------
for (DataSourceInfo dataSourceInfo : allDataSource) {
String name = dataSourceInfo.getHostName() + " " + dataSourceInfo.getDatabaseName(); //根据host databasename组合来查找对应的数据源
com.github.yeecode.dynamicdatasource.model.DataSourceInfo mysqlDynamicDataSourceInfo = new com.github.yeecode.dynamicdatasource.model.DataSourceInfo(name, dataSourceInfo.getDriverClassName(), dataSourceInfo.getUrl(), dataSourceInfo.getUsername(), dataSourceInfo.getPassword());
dynamicDataSource.addDataSource(mysqlDynamicDataSourceInfo, true);
}
//----------------------- Postgres数据源 ---------------------
com.github.yeecode.dynamicdatasource.model.DataSourceInfo pgDynamicDataSourceInfo = new com.github.yeecode.dynamicdatasource.model.DataSourceInfo("postgres", pgDriverClass, pgUrl, pgUserName, pgPassword);
dynamicDataSource.addDataSource(pgDynamicDataSourceInfo, true);
}
操作数据库
public List<CheckResult> check() {
List<CheckResult> resultList = new LinkedList<>(); //存储检查结果
List<CheckResult> dataSourceInfoList = checkResultMapper.listByGroup(); // 根据映射表获取数据源信息
dataSourceInfoService.addDynamicDataSource(dataSourceInfoList); // 新增数据源
List<CheckResult> mappingList = checkResultMapper.findAll();
if (CollectionUtils.isEmpty(mappingList)) {
return null;
}
//----------------------- 根据每个表来查询对应的条数 ---------------------
for (CheckResult checkResult : mappingList) {
String originDatabase = checkResult.getOriginDatabase();
String originDatabaseHost = checkResult.getOriginDatabaseHost();
String originTableName = checkResult.getOriginTableName();
String targetTableName = checkResult.getTargetTableName();
String timeFieldName = checkResult.getTimeFieldName();
String timeFieldValue = checkResult.getTimeFieldValue();
String originCheckSQL = getCheckSQL(originTableName, timeFieldName, timeFieldValue);
String targetCheckSQL = getCheckSQL(targetTableName, timeFieldName, timeFieldValue);
//----------------------- 计算源数据库条数 ---------------------
String datasourceKey = originDatabaseHost + " " + originDatabase; //根据该key来切换数据源
dynamicDataSource.switchDataSource(datasourceKey);
long originCount = commonService.getCount(originCheckSQL); // 源库条数
//----------------------- 计算目标库条数 ---------------------
dynamicDataSource.switchDataSource("postgres");
long targetCount = commonService.getCount(targetCheckSQL); // 目标库条数
//----------------------- 汇总结果 ---------------------
checkResult.setOriginCount(originCount);
checkResult.setTargetCount(targetCount);
checkResult.setSubValue(targetCount - originCount);
if (originCount == targetCount) {
checkResult.setIsCorrect(true);
} else {
checkResult.setIsCorrect(false);
}
resultList.add(checkResult);
}
return resultList;
}
第一次写文章,如有更好建议和意见,请多多指教!