实战责任链设计模式——反向同步关系型数据库(MySQL举例)(3)

接着责任链实现反向同步多数据源数据(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里实现,这里不再赘述!!

 

欢迎 点赞+关注+收藏

谢谢!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值