Flink系列--Flink jdbc connector源码走读

Connector扩展说明

实现一个新的connector用户需要做的事情在上图中Planning部分,其中根据source还是sink来决定实现DynamicTableSourceFactory还是DynamicTableSinkFactory,也可以同时实现这两个接口。

以下针对JdbcDynamicTableFactory源码进行走读:

JdbcDynamicTableFactory类主体结构

public static final String IDENTIFIER = "jdbc";

其他参数见类:JdbcConnectorOptions

public class JdbcConnectorOptions {

    public static final ConfigOption<String> URL =
            ConfigOptions.key("url")
                    .stringType()
                    .noDefaultValue()
                    .withDescription("The JDBC database URL.");

创建source动态表 :createDynamicTableSource

JdbcDynamicTableSource

Lookup与scan接口对比请查看官网:

User-defined Sources & Sinks | Apache Flink

lookup 简单理解为根据提交查找,不必读取整个表,并且可以在需要时从(可能不断变化的)外部表中延迟获取各个值。

scan 在运行时扫描来自外部存储系统的所有行

接下来就是构造如何读取数据库数据的select语句了

1、设置驱动、url,数据库用户名密码等信息

2、设置其他参数,fetchsize,limit,分区条件

3、根据方言构建select,设置数据库中数据类型与flink数据类型映射关系转换器

RuntimeProvider

build返回的为JdbcRowDataInputFormat

 public JdbcRowDataInputFormat build() {
            if (this.queryTemplate == null) {
                throw new NullPointerException("No query supplied");
            }
            if (this.rowConverter == null) {
                throw new NullPointerException("No row converter supplied");
            }
            if (this.parameterValues == null) {
                LOG.debug("No input splitting configured (data will be read with parallelism 1).");
            }
            return new JdbcRowDataInputFormat(
                    new SimpleJdbcConnectionProvider(connOptionsBuilder.build()),
                    this.fetchSize,
                    this.autoCommit,
                    this.parameterValues,
                    this.queryTemplate,
                    this.resultSetType,
                    this.resultSetConcurrency,
                    this.rowConverter,
                    this.rowDataTypeInfo);
        }

JdbcRowDataInputFormat

Connection获取

Connection dbConn = connectionProvider.getOrEstablishConnection();

SimpleJdbcConnectionProvider

 @Override
    public Connection getOrEstablishConnection() throws SQLException, ClassNotFoundException {
        if (connection != null) {
            return connection;
        }
        if (jdbcOptions.getDriverName() == null) {
            connection =
                    DriverManager.getConnection(
                            jdbcOptions.getDbURL(),
                            jdbcOptions.getUsername().orElse(null),
                            jdbcOptions.getPassword().orElse(null));
        } else {
            Driver driver = getLoadedDriver();
            Properties info = new Properties();
            jdbcOptions.getUsername().ifPresent(user -> info.setProperty("user", user));
            jdbcOptions.getPassword().ifPresent(password -> info.setProperty("password", password));
            connection = driver.connect(jdbcOptions.getDbURL(), info);
            if (connection == null) {
                // Throw same exception as DriverManager.getConnection when no driver found to match
                // caller expectation.
                throw new SQLException(
                        "No suitable driver found for " + jdbcOptions.getDbURL(), "08001");
            }
        }
        return connection;
    }

读取一行数据

    /**
     * Stores the next resultSet row in a tuple.
     *
     * @param reuse row to be reused.
     * @return row containing next {@link RowData}
     * @throws IOException
     */
    @Override
    public RowData nextRecord(RowData reuse) throws IOException {
        try {
            if (!hasNext) {
                return null;
            }
            RowData row = rowConverter.toInternal(resultSet);
            // update hasNext after we've read the record
            hasNext = resultSet.next();
            return row;
        } catch (SQLException se) {
            throw new IOException("Couldn't read data - " + se.getMessage(), se);
        } catch (NullPointerException npe) {
            throw new IOException("Couldn't access resultSet", npe);
        }
    }

把resultSet转成rowData

AbstractJdbcRowConverter

  @Override
    public RowData toInternal(ResultSet resultSet) throws SQLException {
        GenericRowData genericRowData = new GenericRowData(rowType.getFieldCount());
        for (int pos = 0; pos < rowType.getFieldCount(); pos++) {
            Object field = resultSet.getObject(pos + 1);
            genericRowData.setField(pos, toInternalConverters[pos].deserialize(field));
        }
        return genericRowData;
    }

Dialect方言选择

根据URL 通过DialectFactory选择方言和driver,并通过继承AbstractDialect实现对应的方言

JdbcDialectFactory识别不同的URL,对应不同的数据库类型

dbcDialect

方言的接口,提供类型验证和类型转换,和insert,update,delete等语句的构造

扩展FLink jdbc connector 支持其它类型的DB数据库

扩展jdbc connector支持其它数据库需要做如下工作

1、DialectFactory实现

2、如下截图中添加上述新的实现类

JdbcDynamicTableFactory如何生效呢?

FactoryUtil中类discoverFactories方法(java SPI机制)

static List<Factory> discoverFactories(ClassLoader classLoader) {
        final List<Factory> result = new LinkedList<>();
        ServiceLoaderUtil.load(Factory.class, classLoader)
                .forEach(
                        loadResult -> {
                            if (loadResult.hasFailed()) {
                                if (loadResult.getError() instanceof NoClassDefFoundError) {
                                    LOG.debug(
                                            "NoClassDefFoundError when loading a "
                                                    + Factory.class
                                                    + ". This is expected when trying to load a format dependency but no flink-connector-files is loaded.",
                                            loadResult.getError());
                                    // After logging, we just ignore this failure
                                    return;
                                }
                                throw new TableException(
                                        "Unexpected error when trying to load service provider for factories.",
                                        loadResult.getError());
                            }
                            result.add(loadResult.getService());
                        });
        return result;
    }

  • 24
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Flink-connector-jdbc是Apache Flink的一个官方连接器,用于将Flink与关系型数据库(如MySQL、PostgreSQL等)进行集成。 要下载Flink-connector-jdbc,可以按照以下步骤进行操作: 1. 打开Apache Flink的官方网站(https://flink.apache.org/)。 2. 导航到"Downloads"(下载)页面,这里提供了Flink的各种版本。 3. 选择所需的Flink版本并下载对应的二进制文件。通常,您可以选择最新的稳定版本。 4. 在下载的Flink二进制文件中,找到一个名为"flink-connector-jdbc"的目录。该目录中包含了Flink与关系型数据库进行连接所需的所有库和文件。 5. 将"flink-connector-jdbc"目录复制到您的工作环境中,以便您可以在Flink应用程序中使用它。 6. 现在,您可以将"flink-connector-jdbc"添加到您的Flink应用程序的依赖中,并开始使用它。 如果您需要使用Maven进行构建,可以在您的Maven配置文件(pom.xml)中添加以下依赖: ``` <dependency> <groupId>org.apache.flink</groupId> <artifactId>flink-connector-jdbc_${scala.binary.version}</artifactId> <version>${flink.version}</version> </dependency> ``` 请注意替换`${scala.binary.version}`和`${flink.version}`为您要使用的具体版本。 下载Flink-connector-jdbc后,您就可以使用它来将Flink与关系型数据库进行集成,实现从数据库中读取数据或将数据写入到数据库中。您可以使用FlinkJDBC连接器来定义数据库表的结构,并使用SQL或DataStream API操作和处理数据库中的数据。通过Flink-connector-jdbc,您可以轻松地利用Flink强大的数据处理能力与关系型数据库进行交互。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值