前言
有需求要建数仓,自然就涉及到数据同步的需求。在这个项目的场景中,需要每天定时从各个业务系统拉取数据到数据仓库。基于这,便设计实施了一个面向sql的ETL工具。
用好三张表
t_etl, t_etl_execute, t_etl_data_source三张表。
t_etl:用于配置etl任务,从哪些源库取什么源数据
t_etl_execute: 对应t_etl中配置的任务,配置目标库,在目标库执行哪些操作
t_etl_data_source:数据源配置信息。
一个简单的示例
从源库的源表t_product_info_0,拉取数据到目标库的目标表t_product_info。
以下重点展示sql相关配置
t_etl的配置:
其中${:id}对应表中的字段名,且按照驼峰规则映射。
这里展示的是一个分页示例,即从表t_product_info_0取数据,分页执行,每次两条,按照id刷选。对于:id初始值配置如下
注意: need_page 配置为true, 这里配置的id是从0开始筛选,框架每次执行查询后会取最后一条记录id值更新。
ps:框架有死循环检查,sql没有分页,但是配置分页了,会自动跳出循环。
t_etl_execute的配置:
注意: ${}中的参数名是对应从源数据表的字段驼峰映射,如果这里使用,那么源数据查询sql中必须包含对应的字段。
可以看出这里包含了两条sql,第一条是插入目标库目标表,第二条是插入历史记录表。那么这两条执行会有顺序要求。
通过order字段配置执行顺序,优先执行数值小的。
对于第一条记录,如果插入失败,需要更新,那么可以配置execute_sql_onfail字段,作为补偿。
以Express结尾的参数名是对应逻辑的参数处理。
需要实现接口,比如示例中uuidExpress的实现如下:
/**
* uuid服务
* @author peter
*
*/
@Component("uuid")
public class UUIDParamHandlerImpl implements ParamHandler<Map, String>{
@Override
public String handle(Map param, JdbcTemplate sourceJdbcTemplate, JdbcTemplate targetJdbcTemplate) {
return UUID.randomUUID().toString();
}
}
注意: @Component(“uuid”),当中命名uuid 或uuidExpress都行。
可以看到这个接口能拿到参数有三个。
第一个param:包含当前行源数据信息
第二个sourceJdbcTemplate:源数据数据库访问模板
第三个targetJdbcTemplate: 目标库数据库访问模板
自此一个简单的示例完成。
扩展
用户可根据自己需要,实现扩展接口ETLHandlerInterceptor
/**
* etl 处理拦截,用户自定义实现
* @author peter
*
*/
public interface ETLHandlerInterceptor {
/**
* 返回false的情况,当前这条etl任务结束
* @param sourceJdbcTemplate
* @param etlDO
* @return
*/
default boolean interceptBefore(JdbcTemplate sourceJdbcTemplate, ETLDO etlDO, Map<String, Object> paramsMap,
List<String> cursorNameList) {
return Boolean.TRUE;
}
/**
* 当前etl任务执行完成后 需要做的处理逻辑
*
* @param sourceJdbcTemplate
* @param etlDO
*/
default void interceptAfter(JdbcTemplate sourceJdbcTemplate, ETLDO etlDO, List<Map<String, Object>> rowList,
Map<String, Object> paramsMap, List<String> cursorNameList) {
}
/**
* 返回false的情况,当前这条etl任务结束
*
* @param sourceJdbcTemplate
* @param etlDO
* @return
*/
default boolean interceptBeforeTarget(JdbcTemplate sourceJdbcTemplate, JdbcTemplate targetJdbcTemplate, ETLDO etlDO,
Map<String, Object> rowMap) {
return Boolean.TRUE;
}
/**
* 当前etl任务执行完成后 需要做的处理逻辑
*
* @param sourceJdbcTemplate
* @param etlDO
*/
default void interceptAfterTarget(JdbcTemplate sourceJdbcTemplate, JdbcTemplate targetJdbcTemplate, ETLDO etlDO,
Map<String, Object> rowMap) {
}
/**
* 返回false的情况,当前这条etl任务结束
*
* @param sourceJdbcTemplate
* @param etlDO
* @return
*/
default boolean interceptBeforeTargetBatch(JdbcTemplate sourceJdbcTemplate, JdbcTemplate targetJdbcTemplate, ETLDO etlDO,
List<Map<String, Object>> rowList) {
return Boolean.TRUE;
}
/**
* 当前etl任务执行完成后 需要做的处理逻辑
*
* @param sourceJdbcTemplate
* @param etlDO
*/
default void interceptAfterTargetBatch(JdbcTemplate sourceJdbcTemplate, JdbcTemplate targetJdbcTemplate, ETLDO etlDO,
List<Map<String, Object>> rowList) {
}
}
支持单行和批处理的扩展处理。此外框架还支持通过配置实现任务链执行。框架默认采用线程池多任务链并行处理。
初版框架已上线,需要优化的还很多,这里展示一些关键信息分享交流。