支持名称大小写转换

This commit is contained in:
inrgihc
2023-08-08 21:27:10 +08:00
parent 24ba0e10d1
commit 7e8a8d9dba
36 changed files with 421 additions and 98 deletions

View File

@@ -9,6 +9,7 @@
/////////////////////////////////////////////////////////////
package com.gitee.dbswitch.data.entity;
import com.gitee.dbswitch.common.type.CaseConvertEnum;
import java.util.concurrent.TimeUnit;
import lombok.Data;
@@ -24,6 +25,8 @@ public class TargetDataSourceProperties {
private Long maxLifeTime = TimeUnit.MINUTES.toMillis(30);
private String targetSchema = "";
private CaseConvertEnum tableNameCase = CaseConvertEnum.NONE;
private CaseConvertEnum columnNameCase = CaseConvertEnum.NONE;
private Boolean targetDrop = Boolean.TRUE;
private Boolean onlyCreate = Boolean.FALSE;
private Boolean createTableAutoIncrement = Boolean.FALSE;

View File

@@ -18,6 +18,7 @@ import com.gitee.dbswitch.calculate.TaskParamEntity;
import com.gitee.dbswitch.common.consts.Constants;
import com.gitee.dbswitch.common.entity.CloseableDataSource;
import com.gitee.dbswitch.common.entity.ResultSetWrapper;
import com.gitee.dbswitch.common.type.CaseConvertEnum;
import com.gitee.dbswitch.common.type.ProductTypeEnum;
import com.gitee.dbswitch.common.util.DatabaseAwareUtils;
import com.gitee.dbswitch.common.util.ExamineUtils;
@@ -118,11 +119,26 @@ public class MigrationHandler implements Supplier<Long> {
fetchSize = sourceProperties.getFetchSize();
}
this.sourceProductType = DatabaseAwareUtils.getProductTypeByDataSource(sourceDataSource);
this.targetProductType = DatabaseAwareUtils.getProductTypeByDataSource(targetDataSource);
if (this.targetProductType.isLikeHive()) {
// !! hive does not support upper table name and column name
properties.getTarget().setTableNameCase(CaseConvertEnum.LOWER);
properties.getTarget().setColumnNameCase(CaseConvertEnum.LOWER);
}
this.targetExistTables = targetExistTables;
// 获取映射转换后新的表名
this.targetSchemaName = properties.getTarget().getTargetSchema();
this.targetTableName = PatterNameUtils.getFinalName(td.getTableName(),
sourceProperties.getRegexTableMapper());
this.targetTableName = properties.getTarget()
.getTableNameCase()
.convert(
PatterNameUtils.getFinalName(
td.getTableName(),
sourceProperties.getRegexTableMapper()
)
);
if (StringUtils.isEmpty(this.targetTableName)) {
throw new RuntimeException("表名的映射规则配置有误,不能将[" + this.sourceTableName + "]映射为空");
@@ -141,10 +157,7 @@ public class MigrationHandler implements Supplier<Long> {
public Long get() {
log.info("Begin Migrate table for {}", tableNameMapString);
this.sourceProductType = DatabaseAwareUtils.getProductTypeByDataSource(sourceDataSource);
this.targetProductType = DatabaseAwareUtils.getProductTypeByDataSource(targetDataSource);
this.sourceMetaDataService = new DefaultMetadataService(sourceDataSource,
sourceProductType);
this.sourceMetaDataService = new DefaultMetadataService(sourceDataSource, sourceProductType);
// 读取源表的表及字段元数据
this.sourceTableRemarks = sourceMetaDataService
@@ -157,9 +170,12 @@ public class MigrationHandler implements Supplier<Long> {
// 根据表的列名映射转换准备目标端表的字段信息
this.targetColumnDescriptions = sourceColumnDescriptions.stream()
.map(column -> {
String newName = PatterNameUtils.getFinalName(
column.getFieldName(),
sourceProperties.getRegexColumnMapper());
String newName = properties.getTarget().getColumnNameCase()
.convert(
PatterNameUtils.getFinalName(
column.getFieldName(),
sourceProperties.getRegexColumnMapper())
);
ColumnDescription description = column.copy();
description.setFieldName(newName);
description.setLabelName(newName);
@@ -167,7 +183,12 @@ public class MigrationHandler implements Supplier<Long> {
}).collect(Collectors.toList());
this.targetPrimaryKeys = sourcePrimaryKeys.stream()
.map(name ->
PatterNameUtils.getFinalName(name, sourceProperties.getRegexColumnMapper())
properties.getTarget().getColumnNameCase()
.convert(
PatterNameUtils.getFinalName(
name,
sourceProperties.getRegexColumnMapper())
)
).collect(Collectors.toList());
// 打印表名与字段名的映射关系

View File

@@ -12,29 +12,20 @@ package com.gitee.dbswitch.data.util;
import cn.hutool.core.util.ClassLoaderUtil;
import com.gitee.dbswitch.common.entity.CloseableDataSource;
import com.gitee.dbswitch.common.entity.InvisibleDataSource;
import com.gitee.dbswitch.common.entity.JarClassLoader;
import com.gitee.dbswitch.common.util.ExamineUtils;
import com.gitee.dbswitch.data.domain.WrapCommonDataSource;
import com.gitee.dbswitch.data.domain.WrapHikariDataSource;
import com.gitee.dbswitch.data.entity.SourceDataSourceProperties;
import com.gitee.dbswitch.data.entity.TargetDataSourceProperties;
import com.zaxxer.hikari.HikariDataSource;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;
import java.util.Objects;
import java.util.Properties;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.sql.DataSource;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
@@ -58,7 +49,8 @@ public final class DataSourceUtils {
* @param properties 数据库连接描述符
* @return HikariDataSource连接池
*/
public static CloseableDataSource createSourceDataSource(SourceDataSourceProperties properties) {
public static CloseableDataSource createSourceDataSource(
SourceDataSourceProperties properties) {
Properties parameters = new Properties();
HikariDataSource ds = new HikariDataSource();
ds.setPoolName("The_Source_DB_Connection");
@@ -102,7 +94,8 @@ public final class DataSourceUtils {
* @param properties 数据库连接描述符
* @return HikariDataSource连接池
*/
public static CloseableDataSource createTargetDataSource(TargetDataSourceProperties properties) {
public static CloseableDataSource createTargetDataSource(
TargetDataSourceProperties properties) {
HikariDataSource ds = new HikariDataSource();
ds.setPoolName("The_Target_DB_Connection");
ds.setJdbcUrl(properties.getUrl());
@@ -151,10 +144,15 @@ public final class DataSourceUtils {
return new WrapHikariDataSource(ds, urlClassLoader);
}
public static CloseableDataSource createCommonDataSource(String jdbcUrl,
String driverClass, String driverPath,
String username, String password) {
URLClassLoader urlClassLoader = createURLClassLoader(driverPath, driverClass);
public static CloseableDataSource createCommonDataSource(
String jdbcUrl,
String driverClass,
String driverPath,
String username,
String password) {
URLClassLoader urlClassLoader = createURLClassLoader(
driverPath,
driverClass);
InvisibleDataSource dataSource = createInvisibleDataSource(
urlClassLoader,
jdbcUrl,
@@ -166,65 +164,46 @@ public final class DataSourceUtils {
return new WrapCommonDataSource(dataSource, urlClassLoader);
}
private static InvisibleDataSource createInvisibleDataSource(ClassLoader cl,
String jdbcUrl, String driverClass, String username,
String password, Properties properties) {
return new InvisibleDataSource(cl, jdbcUrl, driverClass, username, password, properties);
private static InvisibleDataSource createInvisibleDataSource(
ClassLoader cl,
String jdbcUrl,
String driverClass,
String username,
String password,
Properties properties) {
return new InvisibleDataSource(
cl,
jdbcUrl,
driverClass,
username,
password,
properties);
}
private static URLClassLoader createURLClassLoader(String driverPath, String driverClass) {
if (StringUtils.isBlank(driverPath)) {
throw new RuntimeException("Invalid driver path,can not be empty!");
}
if (StringUtils.isBlank(driverClass)) {
throw new RuntimeException("Invalid driver class,can not be empty!");
}
List<Path> filePaths = findJarFilesFromDirectory(driverPath);
if (filePaths.isEmpty()) {
throw new RuntimeException("No jar file found from path:" + driverPath + "!");
}
URL[] urls = filePaths.stream().map(path -> convertPath2URL(path)).toArray(URL[]::new);
private static URLClassLoader createURLClassLoader(
String driverPath, String driverClass) {
ExamineUtils.checkArgument(
StringUtils.isNoneBlank(driverPath),
"Invalid driver path,can not be empty!");
ExamineUtils.checkArgument(
StringUtils.isNoneBlank(driverClass),
"Invalid driver class,can not be empty!");
ClassLoader parent = driverClass.contains("postgresql")
? ClassLoaderUtil.getContextClassLoader()
: ClassLoaderUtil.getSystemClassLoader().getParent();
URLClassLoader loader = new URLClassLoader(urls, parent);
URLClassLoader loader = new JarClassLoader(driverPath, parent);
try {
Class<?> clazz = loader.loadClass(driverClass);
clazz.newInstance();
clazz.getConstructor().newInstance();
return loader;
} catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {
} catch (Exception e) {
log.error("Could not load class : {} from driver path: {}", driverClass, driverPath, e);
throw new RuntimeException(e);
}
}
private static URL convertPath2URL(Path path) {
try {
return path.toUri().toURL();
} catch (MalformedURLException e) {
throw new RuntimeException(e);
}
}
public static List<Path> findJarFilesFromDirectory(String path) {
File file = new File(path);
if (!file.exists()) {
throw new RuntimeException("Path:" + path + " is not exists!");
}
Predicate<Path> fileFilter = f -> {
String fileName = f.toFile().getName();
return fileName.endsWith(".jar") || fileName.endsWith(".JAR");
};
try (Stream<Path> paths = Files.walk(Paths.get(path))) {
return paths.filter(Files::isRegularFile)
.filter(fileFilter)
.collect(Collectors.toList());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private static String executeStringReturnedSql(DataSource dataSource, String sql) {
private static String executeStringReturnedSql(
DataSource dataSource, String sql) {
try (Connection connection = dataSource.getConnection()) {
try (Statement statement = connection.createStatement()) {
try (ResultSet resultSet = statement.executeQuery(sql)) {

View File

@@ -5,7 +5,7 @@ dbswitch:
## support multiple source database connection
- url: jdbc:mysql://172.17.2.10:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=false&zeroDateTimeBehavior=convertToNull&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true&tinyInt1isBit=false&rewriteBatchedStatements=true&useCompression=true
driver-class-name: 'com.mysql.jdbc.Driver'
driver-path: D:/Workspace/dbswitch/drivers/mysql/mysql-5
driver-path: D:\Workspace\IdeaProjects\dbswitch\drivers\mysql\mysql-5
username: 'test'
password: '123456'
# source database configuration parameters
@@ -31,12 +31,14 @@ dbswitch:
## Best support for Oracle/PostgreSQL/Greenplum/DM etc.
url: jdbc:postgresql://172.17.2.10:5432/test
driver-class-name: org.postgresql.Driver
driver-path: D:/Workspace/dbswitch/drivers/postgresql/postgresql-11.4
username: 'test'
driver-path: D:\Workspace\IdeaProjects\dbswitch\drivers\postgresql\postgresql-11.4
username: 'postgres'
password: '123456'
# target database configuration parameters
## schema name for create/insert table data
target-schema: public
table-name-case: UPPER
column-name-case: UPPER
## whether drop-create table when target table exist
target-drop: true
## whether create table support auto increment for primary key field