自定义Flink SourceFunction定时读取数据库

文章目录


前言

Source 是Flink获取数据输入的地方,可以用StreamExecutionEnvironment.addSource(sourceFunction) 将一个 source 关联到你的程序。Flink 自带了许多预先实现的 source functions,不过你仍然可以通过实现 SourceFunction 接口编写自定义的非并行 source,也可以通过实现继承 RichSourceFunction 类编写自定义的 sources。Flink提供了多种预定义的 stream source:基于文件、 套接字、集合等source;但没用提供数据库相关的Source。

有些场景需要定时的读取不断变化的数据库数据作为流数据。本文中的代码实现适用于所有关系数据库。

  • 在构造方法中传递数据库连接参数、定时周期等信息
  • run:在run中定时读取数据库数据并emit到发送到下一节点。
  • cancel: 取消一个 source,running状态改为false将 run 中的循环 emit 元素的行为终止。

二、java代码实现

java 复制代码
/**
 * 关系库流数据源 
 *
 */
public class DbSourceFunction extends RichSourceFunction<Row> {
    private static final long serialVersionUID = 1L;
    private static final Logger LOG = LoggerFactory.getLogger(DbSourceFunction.class);
    private volatile boolean isRunning = true;
    private String driver = null;
    //执行周期(秒)
    private Long period = null;
    private JSONObject conf;
    private DataBaseType baseType;

    public DbFullSourceFunction(JSONObject conf, DataBaseType baseType) {
        this.conf = conf;
        this.baseType = baseType;
        this.driver = baseType.getDriverClassName();
        // 执行周期
        period = conf.getLong("period");
        //周期单位
        String unit = conf.getString("executionWay", "seconds");

        if (period != null && period > 0) {
            //根据时间单位转换为秒
            period = FuntionUtil.getSeconds(unit, period);
        }
    }

    @Override
    public void open(Configuration parameters) throws Exception {
        super.open(parameters);
    }

    @Override
    public void run(SourceContext<Row> ctx) throws Exception {
        while (isRunning) {
            String querySql = conf.getString(Key.QUERY_SQL);
            List<JSONObject> columnList = conf.getList(Key.COLUMN);
            int len = columnList.size();
            Connection connect = null;
            PreparedStatement ps = null;
            ResultSet rs = null;
            try {
                while (connect == null) {
                    try {
                        connect = getConnection();
                        if (connect != null) {
                            break;
                        }
                    } catch (Exception w) {
                        LOG.error("获取连接异常", w.getMessage());
                    }

                }
                ps = connect.prepareStatement(querySql);
                try {
                    rs = ps.executeQuery();
                    while (rs.next()) {
                        Row row = new Row(len);
                        for (int i = 0; i < len; i++) {
                            JSONObject column = columnList.get(i);
                            Integer columnType = column.getInt(Key.COLUMN_TYPE);
							//将ResultSet数据转换为Flink Row
                            RowSetFieldUtil.rowSetFieldResultSet(row, rs, i, columnType, baseType);
                        }
                        // 发送结果
                        ctx.collect(row);
                    }
                } catch (Exception e) {
                    LOG.error("查询出现异常",e);
                    if (ps != null) {
                        ps.close();
                    }
                    if (connect != null) {
                        connect.close();
                    }
                }
            } catch (Exception e) {
                LOG.error("查询数据异常", e);
                throw e;
            } finally {
                if (rs != null) {
                    rs.close();
                }
                if (ps != null) {
                    ps.close();
                }
                if (connect != null) {
                    connect.close();
                }
            }
            if (period == null || period <= 0) {
                isRunning = false;
            } else {
                Long takeTime = (end - start) / 1000;
                //去掉执行消耗时间
                LOG.error("sleep time:" + (period - takeTime));
                TimeUnit.SECONDS.sleep(period - takeTime);
            }

        }
    }

    @Override
    public void cancel() {
        isRunning = false;
    }

    private Connection getConnection() {
        Connection connection = null;
        try {
            String username = conf.getString(Key.USERNAME);
            String password = conf.getString(Key.PASSWORD);
            password = PubFunction.decryptStr(password);
            String jdbcUrl = conf.getString(String.format("%s[0]", Key.JDBC_URL));
            // 创建连接
            connection = DriverManager.getConnection(jdbcUrl, username, password);
        } catch (Exception e) {
            LOG.error("get connection occur exception", e);
            throw new RuntimeException("get connection occur exception", e);
        }
        return connection;
    }
}

总结

完整代码请点击下载自定义Flink SourceFunction定时读取数据库java代码下载

相关推荐
言德斐15 小时前
SQL性能优化的思路及策略
数据库·sql·性能优化
码界奇点15 小时前
Django视图从基础到高级的全面解析
数据库·django·sqlite·web·python3.11
Allan_202515 小时前
数据库学习
数据库·学习
fen_fen15 小时前
人大金仓数据库kingbase8创建表示例
数据库·oracle
一勺菠萝丶15 小时前
「您的连接不是私密连接」详解:为什么 HTTPS 证书会报错,以及如何正确配置子域名证书
数据库·网络协议·https
²º²²এ松16 小时前
蓝牙低功耗(BLE)通信的中心设备/外围设备(连接角色)、主机/从机(时序角色)、客户端/服务器(数据交互角色)的理解
运维·服务器·数据库
百锦再16 小时前
Vue Scoped样式混淆问题详解与解决方案
java·前端·javascript·数据库·vue.js·学习·.net
数据库知识分享者小北17 小时前
云栖重磅|瑶池数据库:从云原生数据底座向“AI就绪”的多模态数据底座演进
数据库·人工智能·云原生
_Johnny_17 小时前
Redis 升级操作指南:单机与主从模式
数据库·redis·缓存
源力祁老师17 小时前
ODOO数据文件(XML、CSV、SQL)是如何转换并加载到 Odoo 数据库
xml·数据库·sql