接着责任链实现反向同步多数据源数据(2)提出的几个具体实现逻辑详细讲解:
一、数据源获取
1.1、厂模式获取具体需要处理的数据源+创建链接
scanHandler = ScanFactory.getScanHandler(reversesyncReq.getComponentId())
ScanFactory:
public final class ScanFactory {
private ScanFactory() {
}
public static final String TABLE = "table";
public static final String VIEW = "view";
public static final String SYNONYM = "synonym";
public static final String PROCEDURE = "PROCEDURE";
public static final String FUNCTION = "FUNCTION";
public static final String PACKAGE = "PACKAGE";
public static final String ADD = "N";
public static final String UPDATE = "U";
/**
*
* @param componentId 数据源ID
* */
public static ScanHandler getScanHandler(Integer componentId) throws Exception {
ScanHandler scanHandler = null;
DataSourceService dataSourceService =
(DataSourceService) SpringContextUtil.getBean("dataSourceService");
DataSource dataSource = dataSourceService.findDataSourceAllById(componentId);
String datasourceType = dataSource.getDatasourceType();
if (datasourceType != null) {
switch (datasourceType) {
case DataSource.GOLDEN_DB:
scanHandler = new GoldenDbScanHandler();
break;
case DataSource.MYSQL:
scanHandler = new MysqlScanHandler();
break;
case DataSource.ORACLE:
scanHandler = new OracleScanHandler();
break;
case DataSource.UDAL:
scanHandler = new UdalScanHandler();
break;
case DataSource.GP:
scanHandler = new GreenPlumScanHandler();
break;
case DataSource.POSTGRESQL:
scanHandler = new PostgreSqlHandler();
break;
case DataSource.ES:
scanHandler = new ElasticSearchHandler();
break;
case DataSource.HIVE:
scanHandler = new HiveScanHandler();
break;
default:
throw new SyDevOpsRuntimeException(I18nUtil.get("databaseTypeNotSupport") + datasourceType);
}
}
// 设置数据源
scanHandler.setDataSource(dataSource);
// 创建连接
scanHandler.buildConnection();
return scanHandler;
}
}
讲解下该方法:scanHandler.buildConnection();
创建连接的抽象在顶层责任链ScanHandler里边定义了抽象方法buildConnection
关系型buildConnection的实现则在关系型抽象ScanAbstractDatabaseHandler
支持驱动jar包选择,支持数据库链接池,并设置超时时间getConnection:
public static Connection getConnection(DataSource datasource, Integer connectTimeout)
throws SQLException, ClassNotFoundException {
switch (datasource.getParamValue(DataSource.Database.IS_POOL)) {
case "1":
// TODO 暂不支持hive
return CorePoolDataSource.getConnection(datasource, connectTimeout);
default:
String datasourceType = null;
String username = null;
String version = null;
String url = null;
String password = null;
String driverName = null;
if (datasource.getConnectMetaData()) {
MetaDataDatasource metaDataDatasource = datasource.getMetaDataDatasource();
datasourceType = metaDataDatasource.getMetaType();
username = metaDataDatasource.getMetaUserName();
url = metaDataDatasource.getMetaUrl();
password = metaDataDatasource.getMetaPassCode();
driverName = metaDataDatasource.getDriverName();
version = metaDataDatasource.getVersion();
}
else {
datasourceType = datasource.getDatasourceType();
username = datasource.getParamValue(DataSource.Database.USERNAME);
version = datasource.getParamValue(DataSource.DRIVER_VERSION);
url = datasource.getParamValue(DataSource.Database.URL);
password = datasource.getParamValue(DataSource.Database.PASSCODE);
driverName = datasource.getParamValue(DataSource.Database.DRIVER_NAME);
}
if (StringUtils.isEmpty(driverName)) {
return getConnection(datasourceType, url, username, password, connectTimeout);
}
else {
// 支持驱动版本选择
return getConnection(datasourceType, driverName, url, username, password, connectTimeout, version);
}
}
}
public static Connection getConnection(String datasourceType, String url, String username, String password,
Integer loginTimeout) throws SQLException {
String datasourceDriver = DatabaseDriver.getDatabaseDriver(url, datasourceType);
if (StringUtils.isEmpty(datasourceDriver)) {
throw new SQLException("This type of database is not supported!");
}
try {
Class.forName(datasourceDriver);
if (!StringUtils.isEmpty(loginTimeout)) {
DriverManager.setLoginTimeout(loginTimeout);
}
return DriverManager.getConnection(url, username, password);
}
catch (Exception e) {
throw new SyDevOpsRuntimeException(e.getMessage(), e);
}
}
1.2、扫描库表信息成功 更新同步进度存Redis
public void updateSyncProcess(ZmgrReversesyncReq zmgrReversesyncReq, Integer currentSize,
Integer totalSize, Integer phase) {
ProcessUtil.computeProcess(zmgrReversesyncReq.getReqId(), currentSize, totalSize, phase);
}
计算同步进度,进度存redis:
/**
* 计算同步进度
*
* @param reqId 请求Id
* @param currentSize
* @param totalSize
* @param phase 阶段表示 1代表扫描阶段 2代表同步阶段
* */
public static Integer computeProcess(Integer reqId, Integer currentSize, Integer totalSize, Integer phase) {
Integer currentProcess = getProcess(reqId);
float actor = EFFECT_ACTOR * 100;
if (phase == 1) {
//扫描阶段
Float f = (currentSize.floatValue() / totalSize.floatValue()) * actor;
currentProcess += f.intValue();
}
else if (phase == 2) {
// 同步阶段
Float f = (currentSize.floatValue() / totalSize.floatValue()) * (100 - actor);
currentProcess += f.intValue();
}
if (currentProcess > 100) {
currentProcess = 100;
}
String key = PROCESS_KEY_PREFIX + reqId;
// 存redis
RedisUtil.putString(key, "" + currentProcess);
return currentProcess;
}
从redis获取进度:
public static Integer getProcess(Integer reqId) {
String key = PROCESS_KEY_PREFIX + reqId;
String value = RedisUtil.getString(key);
if (value == null || "".equals(value)) {
return 0;
}
return Integer.parseInt(value);
}
二、关系型具体Handler实现反向同步举例
以关系型MySQL为例:
2.1、具体Handler实现
public class MysqlScanHandler extends ScanAbstractDatabaseHandler {
private static Map<String, Class<?>> handlers = new HashMap<>();
static {
handlers.put(ScanFactory.TABLE, MysqlScanTableHandler.class);
handlers.put(ScanFactory.VIEW, MysqlScanTableHandler.class);
}
public MysqlScanHandler() {
}
@Override
public List<Map<String, String>> scanAllObjectsInfo() throws Exception {
return DatabaseUtil.findUpperBySql(connection, MysqlSql.getObjectSql(), new String[] {
getSchemaCode().toUpperCase()
});
}
@Override
public Map<String, String> scanObjectInfo(String objectCode, String objectType) throws Exception {
List<Map<String, String>> mapList = DatabaseUtil.findUpperBySql(connection, MysqlSql.getObjectByNameSql(),
new String[] {
getSchemaCode(), objectCode
});
for (Map<String, String> obj : mapList) {
obj.put("OBJECT_TYPE", objectType);
}
if (mapList != null && !mapList.isEmpty()) {
return mapList.get(0);
}
return null;
}
@Override
public List<Map<String, String>> scanTableColumnInfo(Map<String, String> table) throws Exception {
ScanObjectHandler handler = (ScanObjectHandler) handlers.get(table.get("OBJECT_TYPE").toLowerCase()).newInstance();
handler.setScanConnection(connection);
table.put("SCHEMA_CODE", getSchemaCode().toUpperCase());
return handler.findRealColumn(table);
}
/*******************************
* 索引相关操作
*****************************************************************************/
@Override
public List<Map<String, String>> scanTableIndexInfo(Map<String, String> table)
throws Exception {
ScanObjectHandler handler = (ScanObjectHandler) handlers.get(table.get("OBJECT_TYPE").toLowerCase()).newInstance();
handler.setScanConnection(connection);
table.put("SCHEMA_CODE", getSchemaCode().toUpperCase());
return handler.findRealIndex(table);
}
/*******************************
* 约束相关操作
*****************************************************************************/
@Override
public List<Map<String, String>> scanTableConstraintInfo(Map<String, String> table) throws Exception {
MysqlScanTableHandler handler = new MysqlScanTableHandler();
handler.setScanConnection(connection);
table.put("SCHEMA_CODE", getSchemaCode().toUpperCase());
return handler.findRealConstraint(table);
}
@Override
public List<Map<String, String>> scanTablePartitions(Map<String, String> object) throws Exception {
return null;
}
}
2.2、具体Handler操作中的责任链设计,这时候的顶层抽象为具体操作的抽象操作,里边定义了关系型Handler具体操作的责任链
ScanObjectHandler:
public interface ScanObjectHandler {
void setParamVo(ScanParamVO paramVo);
// 连接
void setScanConnection(Connection conn);
// 字段操作
List<Map<String, String>> findRealColumn(Map<String, String> table);
// 索引操作
List<Map<String, String>> findRealIndex(Map<String, String> table);
List<Map<String, String>> findRealConstraint(Map<String, String> table) throws Exception;
List<Map<String, String>> findRealPartitions(Map<String, String> table) throws Exception;
}
例如:索引相关操作:handler.findRealIndex(table);
ScanAbstractObjectHandler实现了顶层抽象ScanObjectHandler
而具体Handler里边实现具体操作责任链的类实现了该抽象:
至此,MysqlScanHandler是执行整个反向同步责任链的某一个Handler,而MysqlScanTableHandler是实现MysqlScanHandler这个具体责任链Handler里边具体业务,例如索引操作,表操作,字段操作的业务责任链实现,这里有两层使用了责任链哦。具体反向同步的业务实现则在MysqlScanTableHandler里实现,这里不再赘述!!
欢迎 点赞+关注+收藏
谢谢!