自定义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代码下载

相关推荐
云飞云共享云桌面7 分钟前
共享云服务器替代传统电脑做三维设计会卡顿吗
大数据·运维·服务器·数据库·自动化
倔强的石头1069 分钟前
数据对话的“通用语法”:SQL与KingbaseES的智能处理艺术
数据库·sql
我科绝伦(Huanhuan Zhou)1 小时前
浅聊达梦数据库物理热备的概念及原理
数据库·oracle
zhz52142 小时前
从PostgreSQL到人大金仓(KingBase)数据库迁移实战:Spring Boot项目完整迁移指南
数据库·spring boot·postgresql
万行3 小时前
点评项目(Redis中间件)&第一部分Redis基础
java·数据库·redis·缓存·中间件
SelectDB3 小时前
Apache Doris 登顶 RTABench —— 实时分析领域的性能王者
数据库·数据分析·开源
用户6279947182623 小时前
南大通用GBase 8a加载常见错误原因
数据库
咸甜适中3 小时前
rust语言(1.88.0)sqlite数据库rusqlite库(0.37.0)学习笔记
数据库·rust·sqlite·rusqlite
Jasonakeke3 小时前
【重学 MySQL】九十二、 MySQL8 密码强度评估与配置指南
android·数据库·mysql
heath ceTide3 小时前
第二章从事件驱动到信号
数据库·系统架构