This is an automated email from the ASF dual-hosted git repository.

fanrui pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/flink-connector-jdbc.git

commit 1bab53304c65384b4fbe6a5fe71de71a344a78fe
Author: Roc Marshal <[email protected]>
AuthorDate: Tue May 28 23:53:27 2024 +0800

    [FLINK-33462][Connector/JDBC] Sort out the document page about the new Jdbc 
source.
---
 docs/content.zh/docs/connectors/datastream/jdbc.md | 486 ++++++++++++++++++++-
 docs/content/docs/connectors/datastream/jdbc.md    | 200 ++++++++-
 2 files changed, 660 insertions(+), 26 deletions(-)

diff --git a/docs/content.zh/docs/connectors/datastream/jdbc.md 
b/docs/content.zh/docs/connectors/datastream/jdbc.md
index a57cf0bb..fddaa9f6 100644
--- a/docs/content.zh/docs/connectors/datastream/jdbc.md
+++ b/docs/content.zh/docs/connectors/datastream/jdbc.md
@@ -26,38 +26,341 @@ under the License.
 
 # JDBC Connector
 
-该连接器可以向 JDBC 数据库写入数据。
+This connector provides a source that read data from a JDBC database and
+provides a sink that writes data to a JDBC database.
 
-添加下面的依赖以便使用该连接器(同时添加 JDBC 驱动):
+To use it, add the following dependency to your project (along with your JDBC 
driver):
 
 {{< connector_artifact flink-connector-jdbc jdbc >}}
 
-注意该连接器目前还 __不是__ 二进制发行版的一部分,如何在集群中运行请参考 [这里]({{< ref 
"docs/dev/configuration/overview" >}})。
+Note that the streaming connectors are currently __NOT__ part of the binary 
distribution.
+See how to link with them for cluster execution [here]({{< ref 
"docs/dev/configuration/overview" >}}).
+A driver dependency is also required to connect to a specified database.
+Please consult your database documentation on how to add the corresponding 
driver.
 
-已创建的 JDBC Sink 能够保证至少一次的语义。
-更有效的精确执行一次可以通过 upsert 语句或幂等更新实现。
+## JDBC Source
 
-用法示例:
-{{< tabs "4ab65f13-608a-411a-8d24-e303f384ab5d" >}}
+Configuration goes as follow (see also {{< javadoc 
file="org/apache/flink/connector/jdbc/source/JdbcSource.html" name="JdbcSource 
javadoc" >}}
+and {{< javadoc 
file="org/apache/flink/connector/jdbc/source/JdbcSourceBuilder.html" 
name="JdbcSourceBuilder javadoc" >}}).
+
+### Usage
+
+{{< tabs "4ab65f13-607a-411a-8d24-e709f701cd41" >}}
 {{< tab "Java" >}}
 ```java
+JdbcSource source = JdbcSourceBuilder.builder()
+        // Required
+        .setSql(...)
+        .setResultExtractor(...)
+        .setUsername(...)
+        .setPassword(...)
+        .setDriverName(...)
+        .setDBUrl(...)
+        .setTypeInformation(...)
+        
+         // Optional
+        .setContinuousUnBoundingSettings(...)
+        .setJdbcParameterValuesProvider(...)
+        .setDeliveryGuarantee(...)
+        .setConnectionCheckTimeoutSeconds(...)
+        
+        // The extended JDBC connection property passing
+        .setConnectionProperty("key", "value")
+        
+        // other attributes
+        .setSplitReaderFetchBatchSize(...)
+        .setResultSetType(...)
+        .setResultSetConcurrency(...)
+        .setAutoCommit(...)
+        .setResultSetFetchSize(...)
+        .setConnectionProvider(...)
+        .build();
+
+```
+{{< /tab >}}
+{{< tab "Python" >}}
+```python
+Still not supported in Python API.
+```
+{{< /tab >}}
+{{< /tabs >}}
+
+### Delivery guarantee
+
+The JDBC source provides 
`at-least-once`/`at-most-once(default)`/`exactly-once` guarantee.
+The `JdbcSource` supports `Delivery guarantee` semantic based on `Concur` of 
`ResultSet`.
+
+**NOTE:** Here's a few disadvantage. It only makes sense for corresponding 
semantic
+that the `ResultSet` corresponding to this SQL(`JdbcSourceSplit`)
+remains unchanged in the whole lifecycle of `JdbcSourceSplit` processing.
+Unfortunately, this condition is not met in most databases and data scenarios.
+See 
[FLIP-239](https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=217386271)
 for more details.
+
+### ResultExtractor
+
+An `Extractor` to extract a record from `ResultSet` executed by a sql.
+
+```java
+import org.apache.flink.connector.jdbc.source.reader.extractor.ResultExtractor;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+class Book {
+    public Book(Long id, String title) {
+        this.id = id;
+        this.title = title;
+    }
+
+    final Long id;
+    final String title;
+};
+
+ResultExtractor resultExtractor = new ResultExtractor() {
+    @Override
+    public Object extract(ResultSet resultSet) throws SQLException {
+        return new Book(resultSet.getLong("id"), 
resultSet.getString("titile"));
+    }
+};
+
+```
+
+### JdbcParameterValuesProvider
+
+A provider to provide parameters in sql to fulfill actual value in the 
corresponding placeholders, which is in the form of two-dimension array.
+See {{< javadoc 
file="org/apache/flink/connector/jdbc/split/JdbcParameterValuesProvider.html" 
name="JdbcParameterValuesProvider javadoc" >}} for more details.
+
+```java
+
+class TestEntry {
+    ...
+};
+
+ResultSetExtractor extractor = ...;
+
 StreamExecutionEnvironment env = 
StreamExecutionEnvironment.getExecutionEnvironment();
-env
-        .fromElements(...)
-        .addSink(JdbcSink.sink(
-                "insert into books (id, title, author, price, qty) values 
(?,?,?,?,?)",
-                (ps, t) -> {
-                    ps.setInt(1, t.id);
-                    ps.setString(2, t.title);
-                    ps.setString(3, t.author);
-                    ps.setDouble(4, t.price);
-                    ps.setInt(5, t.qty);
-                },
-                new JdbcConnectionOptions.JdbcConnectionOptionsBuilder()
-                        .withUrl(getDbMetadata().getUrl())
-                        .withDriverName(getDbMetadata().getDriverClass())
-                        .build()));
+
+JdbcSource<TestEntry> jdbcSource =
+        JdbcSource.<TestEntry>builder()
+                .setTypeInformation(TypeInformation.of(TestEntry.class))
+                .setSql("select * from testing_table where id >= ? and id <= 
?")
+                .setJdbcParameterValuesProvider(
+                        new JdbcGenericParameterValuesProvider(
+                                new Serializable[][] {{1001, 1005}, {1006, 
1010}}))
+                ...
+                .build();
+env.fromSource(jdbcSource, WatermarkStrategy.noWatermarks(), "TestSource")
+        .addSink(new DiscardSink());
 env.execute();
+
+```
+
+### Minimalist Streaming Semantic and ContinuousUnBoundingSettings
+
+If you want to generate continuous milliseconds parameters based on 
sliding-window,
+please have a try on setting the followed attributes of `JdbcSource`:
+
+```java
+
+jdbcSourceBuilder =
+        JdbcSource.<TestEntry>builder()
+        .setSql("select * from testing_table where ts >= ? and ts < ?")
+        
+        // Required for streaming related semantic.
+        .setContinuousUnBoundingSettings(new 
ContinuousUnBoundingSettings(Duration.ofMillis(10L), Duration.ofSeconds(1L)))
+        .setJdbcParameterValuesProvider(new 
JdbcSlideTimingParameterProvider(0L, 1000L, 1000L, 100L))
+        .setDeliveryGuarantee(DeliveryGuarantee.EXACTLY_ONCE)
+        .setResultSetType(ResultSet.TYPE_SCROLL_INSENSITIVE);
+
+        // other attributes
+        ...
+        
+JdbcSource source = jdbcSourceBuilder.build();
+```
+
+See {{< javadoc 
file="org/apache/flink/connector/jdbc/utils/ContinuousUnBoundingSettings.html" 
name="ContinuousUnBoundingSettings javadoc" >}} for more details.
+
+### Full example
+
+{{< tabs "4ab65f13-608a-411a-8d24-e303f348ds81" >}}
+{{< tab "Java" >}}
+
+```java
+
+public class JdbcSourceExample {
+
+    static class Book {
+        public Book(Long id, String title) {
+            this.id = id;
+            this.title = title;
+        }
+
+        final Long id;
+        final String title;
+    };
+
+    public static void main(String[] args) throws Exception {
+        StreamExecutionEnvironment env = 
StreamExecutionEnvironment.getExecutionEnvironment();
+        JdbcSource<Book> jdbcSource =
+                JdbcSource.<Book>builder()
+                        .setTypeInformation(TypeInformation.of(Book.class))
+                        .setSql("select * from testing_table where id < ?")
+                        .setDBUrl(...)
+                        .setJdbcParameterValuesProvider(
+                                new JdbcGenericParameterValuesProvider(
+                                        new Serializable[][] {{1001L}}))
+                        .setDriverName(...)
+                        .setResultExtractor(resultSet ->
+                            new Book(
+                                resultSet.getLong("id"),
+                                resultSet.getString("title")))
+                .build();
+        env.fromSource(jdbcSource, WatermarkStrategy.noWatermarks(), 
"TestSource")
+                .addSink(new DiscardingSink());
+        env.execute();
+    }
+}
+```
+{{< /tab >}}
+{{< tab "Python" >}}
+```python
+Still not supported in Python API.
+```
+{{< /tab >}}
+{{< /tabs >}}
+
+## `JdbcSink.sink`
+
+The JDBC sink provides at-least-once guarantee.
+Effectively though, exactly-once can be achieved by crafting upsert SQL 
statements or idempotent SQL updates.
+Configuration goes as follow (see also {{< javadoc 
file="org/apache/flink/connector/jdbc/JdbcSink.html" name="JdbcSink javadoc" 
>}}).
+
+{{< tabs "4ab65f13-607a-411a-8d24-e709f701cd4c" >}}
+{{< tab "Java" >}}
+```java
+JdbcSink.sink(
+       sqlDmlStatement,                       // mandatory
+       jdbcStatementBuilder,                  // mandatory     
+       jdbcExecutionOptions,                  // optional
+       jdbcConnectionOptions                  // mandatory
+);
+```
+{{< /tab >}}
+{{< tab "Python" >}}
+```python
+JdbcSink.sink(
+    sql_dml_statement,          # mandatory
+    type_info,                  # mandatory
+    jdbc_connection_options,    # mandatory
+    jdbc_execution_options      # optional
+)
+```
+{{< /tab >}}
+{{< /tabs >}}
+
+### SQL DML statement and JDBC statement builder
+
+The sink builds one [JDBC prepared 
statement](https://docs.oracle.com/en/java/javase/11/docs/api/java.sql/java/sql/PreparedStatement.html)
 from a user-provider SQL string, e.g.:
+
+```sql
+INSERT INTO some_table field1, field2 values (?, ?)
+```
+
+It then repeatedly calls a user-provided function to update that prepared 
statement with each value of the stream, e.g.:
+
+```
+(preparedStatement, someRecord) -> { ... update here the preparedStatement 
with values from someRecord ... }
+```
+
+### JDBC execution options
+
+The SQL DML statements are executed in batches, which can optionally be 
configured with the following instance (see also {{< javadoc 
name="JdbcExecutionOptions javadoc" 
file="org/apache/flink/connector/jdbc/JdbcExecutionOptions.html" >}})
+
+{{< tabs "4ab65f13-607a-411a-8d24-e709f512ed6k" >}}
+{{< tab "Java" >}}
+```java
+JdbcExecutionOptions.builder()
+        .withBatchIntervalMs(200)             // optional: default = 0, 
meaning no time-based execution is done
+        .withBatchSize(1000)                  // optional: default = 5000 
values
+        .withMaxRetries(5)                    // optional: default = 3 
+.build();
+```
+{{< /tab >}}
+{{< tab "Python" >}}
+```python
+JdbcExecutionOptions.builder() \
+    .with_batch_interval_ms(2000) \
+    .with_batch_size(100) \
+    .with_max_retries(5) \
+    .build()
+```
+{{< /tab >}}
+{{< /tabs >}}
+
+A JDBC batch is executed as soon as one of the following conditions is true:
+
+* the configured batch interval time is elapsed
+* the maximum batch size is reached 
+* a Flink checkpoint has started
+
+### JDBC connection parameters
+
+The connection to the database is configured with a `JdbcConnectionOptions` 
instance. 
+Please see {{< javadoc name="JdbcConnectionOptions javadoc" 
file="org/apache/flink/connector/jdbc/JdbcConnectionOptions.html" >}} for 
details
+
+### Full example
+
+{{< tabs "4ab65f13-608a-411a-8d24-e303f348ds8d" >}}
+{{< tab "Java" >}}
+```java
+public class JdbcSinkExample {
+
+    static class Book {
+        public Book(Long id, String title, String authors, Integer year) {
+            this.id = id;
+            this.title = title;
+            this.authors = authors;
+            this.year = year;
+        }
+        final Long id;
+        final String title;
+        final String authors;
+        final Integer year;
+    }
+
+    public static void main(String[] args) throws Exception {
+        var env = StreamExecutionEnvironment.getExecutionEnvironment();
+
+        env.fromElements(
+                new Book(101L, "Stream Processing with Apache Flink", "Fabian 
Hueske, Vasiliki Kalavri", 2019),
+                new Book(102L, "Streaming Systems", "Tyler Akidau, Slava 
Chernyak, Reuven Lax", 2018),
+                new Book(103L, "Designing Data-Intensive Applications", 
"Martin Kleppmann", 2017),
+                new Book(104L, "Kafka: The Definitive Guide", "Gwen Shapira, 
Neha Narkhede, Todd Palino", 2017)
+        ).addSink(
+                JdbcSink.sink(
+                        "insert into books (id, title, authors, year) values 
(?, ?, ?, ?)",
+                        (statement, book) -> {
+                            statement.setLong(1, book.id);
+                            statement.setString(2, book.title);
+                            statement.setString(3, book.authors);
+                            statement.setInt(4, book.year);
+                        },
+                        JdbcExecutionOptions.builder()
+                                .withBatchSize(1000)
+                                .withBatchIntervalMs(200)
+                                .withMaxRetries(5)
+                                .build(),
+                        new 
JdbcConnectionOptions.JdbcConnectionOptionsBuilder()
+                                
.withUrl("jdbc:postgresql://dbhost:5432/postgresdb")
+                                .withDriverName("org.postgresql.Driver")
+                                .withUsername("someUser")
+                                .withPassword("somePassword")
+                                .build()
+                ));
+                
+        env.execute();
+    }
+}
 ```
 {{< /tab >}}
 {{< tab "Python" >}}
@@ -79,6 +382,11 @@ env.from_collection(
             .with_driver_name('org.postgresql.Driver')
             .with_user_name('someUser')
             .with_password('somePassword')
+            .build(),
+        JdbcExecutionOptions.builder()
+            .with_batch_interval_ms(1000)
+            .with_batch_size(200)
+            .with_max_retries(5)
             .build()
     ))
 
@@ -87,4 +395,136 @@ env.execute()
 {{< /tab >}}
 {{< /tabs >}}
 
-更多细节请查看 API documentation 。
+## `JdbcSink.exactlyOnceSink`
+
+Since 1.13, Flink JDBC sink supports exactly-once mode. 
+The implementation relies on the JDBC driver support of XA 
+[standard](https://pubs.opengroup.org/onlinepubs/009680699/toc.pdf).
+Most drivers support XA if the database also supports XA (so the driver is 
usually the same).
+
+To use it, create a sink using `exactlyOnceSink()` method as above and 
additionally provide:
+- {{< javadoc name="exactly-once options" 
file="org/apache/flink/connector/jdbc/JdbcExactlyOnceOptions.html" >}}
+- {{< javadoc name="execution options" 
file="org/apache/flink/connector/jdbc/JdbcExecutionOptions.html" >}}
+- [XA 
DataSource](https://docs.oracle.com/javase/8/docs/api/javax/sql/XADataSource.html)
 Supplier
+
+For example:
+
+{{< tabs "4ab65f13-608a-411a-8d24-e304f627ac8f" >}}
+{{< tab "Java" >}}
+```java
+StreamExecutionEnvironment env = 
StreamExecutionEnvironment.getExecutionEnvironment();
+env
+        .fromElements(...)
+        .addSink(JdbcSink.exactlyOnceSink(
+                "insert into books (id, title, author, price, qty) values 
(?,?,?,?,?)",
+                (ps, t) -> {
+                    ps.setInt(1, t.id);
+                    ps.setString(2, t.title);
+                    ps.setString(3, t.author);
+                    ps.setDouble(4, t.price);
+                    ps.setInt(5, t.qty);
+                },
+                JdbcExecutionOptions.builder()
+                    .withMaxRetries(0)
+                    .build(),
+                JdbcExactlyOnceOptions.defaults(),
+                () -> {
+                    // create a driver-specific XA DataSource
+                    // The following example is for derby 
+                    EmbeddedXADataSource ds = new EmbeddedXADataSource();
+                    ds.setDatabaseName("my_db");
+                    return ds;
+                });
+env.execute();
+```
+{{< /tab >}}
+{{< tab "Python" >}}
+```python
+Still not supported in Python API.
+```
+{{< /tab >}}
+{{< /tabs >}}
+
+**NOTE:** Some databases only allow a single XA transaction per connection 
(e.g. PostgreSQL, MySQL).
+In such cases, please use the following API to construct 
`JdbcExactlyOnceOptions`:
+
+{{< tabs "4ab65f13-608a-411a-8d24-e304f627cd4e" >}}
+{{< tab "Java" >}}
+```java
+JdbcExactlyOnceOptions.builder()
+.withTransactionPerConnection(true)
+.build();
+```
+{{< /tab >}}
+{{< tab "Python" >}}
+```python
+Still not supported in Python API.
+```
+{{< /tab >}}
+{{< /tabs >}}
+
+This will make Flink use a separate connection for every XA transaction. This 
may require adjusting connection limits.
+For PostgreSQL and MySQL, this can be done by increasing `max_connections`.
+
+Furthermore, XA needs to be enabled and/or configured in some databases.
+For PostgreSQL, you should set `max_prepared_transactions` to some value 
greater than zero.
+For MySQL v8+, you should grant `XA_RECOVER_ADMIN` to Flink DB user.
+
+**ATTENTION:** Currently, `JdbcSink.exactlyOnceSink` can ensure exactly once 
semantics
+with `JdbcExecutionOptions.maxRetries == 0`; otherwise, duplicated results 
maybe produced.
+
+### `XADataSource` examples
+PostgreSQL `XADataSource` example:
+{{< tabs "4ab65f13-608a-411a-8d24-e304f323ab3a" >}}
+{{< tab "Java" >}}
+```java
+PGXADataSource xaDataSource = new org.postgresql.xa.PGXADataSource();
+xaDataSource.setUrl("jdbc:postgresql://localhost:5432/postgres");
+xaDataSource.setUser(username);
+xaDataSource.setPassword(password);
+```
+{{< /tab >}}
+{{< tab "Python" >}}
+```python
+Still not supported in Python API.
+```
+{{< /tab >}}
+{{< /tabs >}}
+
+MySQL `XADataSource` example:
+{{< tabs "4ab65f13-608a-411a-8d24-b213f323ca3c" >}}
+{{< tab "Java" >}}
+```java
+MysqlXADataSource xaDataSource = new com.mysql.cj.jdbc.MysqlXADataSource();
+xaDataSource.setUrl("jdbc:mysql://localhost:3306/");
+xaDataSource.setUser(username);
+xaDataSource.setPassword(password);
+```
+{{< /tab >}}
+{{< tab "Python" >}}
+```python
+Still not supported in Python API.
+```
+{{< /tab >}}
+{{< /tabs >}}
+
+Oracle `XADataSource` example:
+{{< tabs "4ab65f13-608a-411a-8d24-b213f337ad5f" >}}
+{{< tab "Java" >}}
+```java
+OracleXADataSource xaDataSource = new oracle.jdbc.xa.OracleXADataSource();
+xaDataSource.setURL("jdbc:oracle:oci8:@");
+xaDataSource.setUser("scott");
+xaDataSource.setPassword("tiger");
+```
+{{< /tab >}}
+{{< tab "Python" >}}
+```python
+Still not supported in Python API.
+```
+{{< /tab >}}
+{{< /tabs >}}
+
+Please also take Oracle connection pooling into account.
+
+Please refer to the `JdbcXaSinkFunction` documentation for more details.
diff --git a/docs/content/docs/connectors/datastream/jdbc.md 
b/docs/content/docs/connectors/datastream/jdbc.md
index 41e46fb8..05babddc 100644
--- a/docs/content/docs/connectors/datastream/jdbc.md
+++ b/docs/content/docs/connectors/datastream/jdbc.md
@@ -26,14 +26,208 @@ under the License.
 
 # JDBC Connector
 
-This connector provides a sink that writes data to a JDBC database.
+This connector provides a source that read data from a JDBC database and
+provides a sink that writes data to a JDBC database.
 
 To use it, add the following dependency to your project (along with your JDBC 
driver):
 
 {{< connector_artifact flink-connector-jdbc jdbc >}}
 
-Note that the streaming connectors are currently __NOT__ part of the binary 
distribution. See how to link with them for cluster execution [here]({{< ref 
"docs/dev/configuration/overview" >}}).
-A driver dependency is also required to connect to a specified database. 
Please consult your database documentation on how to add the corresponding 
driver.
+Note that the streaming connectors are currently __NOT__ part of the binary 
distribution.
+See how to link with them for cluster execution [here]({{< ref 
"docs/dev/configuration/overview" >}}).
+A driver dependency is also required to connect to a specified database.
+Please consult your database documentation on how to add the corresponding 
driver.
+
+## JDBC Source
+
+Configuration goes as follow (see also {{< javadoc 
file="org/apache/flink/connector/jdbc/source/JdbcSource.html" name="JdbcSource 
javadoc" >}}
+and {{< javadoc 
file="org/apache/flink/connector/jdbc/source/JdbcSourceBuilder.html" 
name="JdbcSourceBuilder javadoc" >}}).
+
+### Usage
+
+{{< tabs "4ab65f13-607a-411a-8d24-e709f701cd41" >}}
+{{< tab "Java" >}}
+```java
+JdbcSource source = JdbcSourceBuilder.builder()
+        // Required
+        .setSql(...)
+        .setResultExtractor(...)
+        .setUsername(...)
+        .setPassword(...)
+        .setDriverName(...)
+        .setDBUrl(...)
+        .setTypeInformation(...)
+        
+         // Optional
+        .setContinuousUnBoundingSettings(...)
+        .setJdbcParameterValuesProvider(...)
+        .setDeliveryGuarantee(...)
+        .setConnectionCheckTimeoutSeconds(...)
+        
+        // The extended JDBC connection property passing
+        .setConnectionProperty("key", "value")
+        
+        // other attributes
+        .setSplitReaderFetchBatchSize(...)
+        .setResultSetType(...)
+        .setResultSetConcurrency(...)
+        .setAutoCommit(...)
+        .setResultSetFetchSize(...)
+        .setConnectionProvider(...)
+        .build();
+
+```
+{{< /tab >}}
+{{< tab "Python" >}}
+```python
+Still not supported in Python API.
+```
+{{< /tab >}}
+{{< /tabs >}}
+
+### Delivery guarantee
+
+The JDBC source provides 
`at-least-once`/`at-most-once(default)`/`exactly-once` guarantee.
+The `JdbcSource` supports `Delivery guarantee` semantic based on `Concur` of 
`ResultSet`.
+
+**NOTE:** Here's a few disadvantage. It only makes sense for corresponding 
semantic
+that the `ResultSet` corresponding to this SQL(`JdbcSourceSplit`)
+remains unchanged in the whole lifecycle of `JdbcSourceSplit` processing.
+Unfortunately, this condition is not met in most databases and data scenarios.
+See 
[FLIP-239](https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=217386271)
 for more details.
+
+### ResultExtractor
+
+An `Extractor` to extract a record from `ResultSet` executed by a sql.
+
+```java
+import org.apache.flink.connector.jdbc.source.reader.extractor.ResultExtractor;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+class Book {
+    public Book(Long id, String title) {
+        this.id = id;
+        this.title = title;
+    }
+
+    final Long id;
+    final String title;
+};
+
+ResultExtractor resultExtractor = new ResultExtractor() {
+    @Override
+    public Object extract(ResultSet resultSet) throws SQLException {
+        return new Book(resultSet.getLong("id"), 
resultSet.getString("titile"));
+    }
+};
+
+```
+
+### JdbcParameterValuesProvider
+
+A provider to provide parameters in sql to fulfill actual value in the 
corresponding placeholders, which is in the form of two-dimension array.
+See {{< javadoc 
file="org/apache/flink/connector/jdbc/split/JdbcParameterValuesProvider.html" 
name="JdbcParameterValuesProvider javadoc" >}} for more details.
+
+```java
+
+class TestEntry {
+    ...
+};
+
+ResultSetExtractor extractor = ...;
+
+StreamExecutionEnvironment env = 
StreamExecutionEnvironment.getExecutionEnvironment();
+
+JdbcSource<TestEntry> jdbcSource =
+        JdbcSource.<TestEntry>builder()
+                .setTypeInformation(TypeInformation.of(TestEntry.class))
+                .setSql("select * from testing_table where id >= ? and id <= 
?")
+                .setJdbcParameterValuesProvider(
+                        new JdbcGenericParameterValuesProvider(
+                                new Serializable[][] {{1001, 1005}, {1006, 
1010}}))
+                ...
+                .build();
+env.fromSource(jdbcSource, WatermarkStrategy.noWatermarks(), "TestSource")
+        .addSink(new DiscardSink());
+env.execute();
+
+```
+
+### Minimalist Streaming Semantic and ContinuousUnBoundingSettings
+
+If you want to generate continuous milliseconds parameters based on 
sliding-window,
+please have a try on setting the followed attributes of `JdbcSource`:
+
+```java
+
+jdbcSourceBuilder =
+        JdbcSource.<TestEntry>builder()
+        .setSql("select * from testing_table where ts >= ? and ts < ?")
+        
+        // Required for streaming related semantic.
+        .setContinuousUnBoundingSettings(new 
ContinuousUnBoundingSettings(Duration.ofMillis(10L), Duration.ofSeconds(1L)))
+        .setJdbcParameterValuesProvider(new 
JdbcSlideTimingParameterProvider(0L, 1000L, 1000L, 100L))
+        .setDeliveryGuarantee(DeliveryGuarantee.EXACTLY_ONCE)
+        .setResultSetType(ResultSet.TYPE_SCROLL_INSENSITIVE);
+
+        // other attributes
+        ...
+        
+JdbcSource source = jdbcSourceBuilder.build();
+```
+
+See {{< javadoc 
file="org/apache/flink/connector/jdbc/utils/ContinuousUnBoundingSettings.html" 
name="ContinuousUnBoundingSettings javadoc" >}} for more details.
+
+### Full example
+
+{{< tabs "4ab65f13-608a-411a-8d24-e303f348ds81" >}}
+{{< tab "Java" >}}
+
+```java
+
+public class JdbcSourceExample {
+
+    static class Book {
+        public Book(Long id, String title) {
+            this.id = id;
+            this.title = title;
+        }
+
+        final Long id;
+        final String title;
+    };
+
+    public static void main(String[] args) throws Exception {
+        StreamExecutionEnvironment env = 
StreamExecutionEnvironment.getExecutionEnvironment();
+        JdbcSource<Book> jdbcSource =
+                JdbcSource.<Book>builder()
+                        .setTypeInformation(TypeInformation.of(Book.class))
+                        .setSql("select * from testing_table where id < ?")
+                        .setDBUrl(...)
+                        .setJdbcParameterValuesProvider(
+                                new JdbcGenericParameterValuesProvider(
+                                        new Serializable[][] {{1001L}}))
+                        .setDriverName(...)
+                        .setResultExtractor(resultSet ->
+                            new Book(
+                                resultSet.getLong("id"),
+                                resultSet.getString("title")))
+                .build();
+        env.fromSource(jdbcSource, WatermarkStrategy.noWatermarks(), 
"TestSource")
+                .addSink(new DiscardingSink());
+        env.execute();
+    }
+}
+```
+{{< /tab >}}
+{{< tab "Python" >}}
+```python
+Still not supported in Python API.
+```
+{{< /tab >}}
+{{< /tabs >}}
 
 ## `JdbcSink.sink`
 

Reply via email to