Import data using Flink

Updated at:
Copy as MD

The Flink Doris Connector bridges Apache Flink and ApsaraDB for SelectDB, letting you stream data from relational databases (MySQL, Oracle, PostgreSQL, SQL Server) and message queues (Kafka) into SelectDB in real time. Because SelectDB is fully compatible with Apache Doris, the connector works without additional configuration.

This topic covers three import methods: Flink SQL, Flink CDC, and the DataStream API.

The Flink Doris Connector supports writes to SelectDB only. To read from SelectDB backend (BE) nodes directly, contact SelectDB technical support. To read data from SelectDB, use the Flink Java Database Connectivity (JDBC) Connector instead.

How it works

Flink stream processing consists of three stages:

  • Source — reads data from an external system (a database, Kafka topic, or file system).

  • Transform — filters, maps, aggregates, or windows the incoming data.

  • Sink — writes the processed data to an external system. The Flink Doris Connector acts as the sink, writing to SelectDB via Stream Load.

The following diagram shows the data flow when importing data into SelectDB using the Flink Doris Connector.

image

Prerequisites

Before you begin, ensure that you have:

Version requirements

Flink versionFlink Doris Connector versionDownload
Realtime Compute for Apache Flink: 1.17 or later; open source: 1.15 or later1.5.2 or later (latest recommended)Maven repository

Install the Flink Doris Connector

Choose the installation method that matches your Flink setup.

Realtime Compute for Apache Flink

Use the custom connector feature to upload and manage the Flink Doris Connector JAR. For details, see Manage custom connectors.

Self-managed open-source Flink cluster

Download the JAR for your connector version from the Maven repository and place it in the lib directory of your Flink installation.

JAR naming format: flink-doris-connector-{flink_version}-{connector_version}.jar

Example for Flink 1.16 with connector 1.5.2:

flink-doris-connector-1.16-1.5.2.jar

Maven project

Add the following dependency to your pom.xml. For other versions, see the Maven repository.

<!-- Flink Doris Connector -->
<dependency>
  <groupId>org.apache.doris</groupId>
  <artifactId>flink-doris-connector-1.16</artifactId>
  <version>1.5.2</version>
</dependency>

Usage examples

The following examples migrate data from the employees table in the test database of a MySQL instance to the employees table in the test database of a SelectDB instance. All examples use a Flink 1.16 standalone environment.

Set up the environment

Set up Flink

  1. Install Java 8 and configure the JAVA_HOME environment variable. For supported Java versions per Flink release, see Java compatibility. For installation instructions, see Install JDK.

  2. Download the Flink installation package.

    wget https://www.apache.si/flink/flink-1.16.3/flink-1.16.3-bin-scala_2.12.tgz

    For other versions, see Apache Flink downloads.

  3. Decompress the package.

    tar -zxvf flink-1.16.3-bin-scala_2.12.tgz
  4. From the lib directory of your Flink installation, download the required connectors.

    # Flink Doris Connector
    wget https://repo.maven.apache.org/maven2/org/apache/doris/flink-doris-connector-1.16/1.5.2/flink-doris-connector-1.16-1.5.2.jar
    
    # Flink MySQL CDC Connector
    wget https://repo1.maven.org/maven2/com/ververica/flink-sql-connector-mysql-cdc/2.4.2/flink-sql-connector-mysql-cdc-2.4.2.jar
  5. Start the Flink cluster from the bin directory.

    ./start-cluster.sh

Set up the SelectDB destination table

  1. Create an ApsaraDB for SelectDB instance.

  2. Connect to the instance.

  3. Create the destination database and table.

    CREATE DATABASE test;
    USE test;
    
    CREATE TABLE employees (
        emp_no       int NOT NULL,
        birth_date   date,
        first_name   varchar(20),
        last_name    varchar(20),
        gender       char(2),
        hire_date    date
    )
    UNIQUE KEY(`emp_no`)
    DISTRIBUTED BY HASH(`emp_no`) BUCKETS 1;

Set up the MySQL source table

  1. Create an ApsaraDB RDS for MySQL instance.

  2. Create the source database and table, then insert sample data.

    CREATE DATABASE test;
    USE test;
    
    CREATE TABLE employees (
        emp_no INT NOT NULL PRIMARY KEY,
        birth_date DATE,
        first_name VARCHAR(20),
        last_name VARCHAR(20),
        gender CHAR(2),
        hire_date DATE
    );
    
    INSERT INTO employees (emp_no, birth_date, first_name, last_name, gender, hire_date) VALUES
    (1001, '1985-05-15', 'John', 'Doe', 'M', '2010-06-20'),
    (1002, '1990-08-22', 'Jane', 'Smith', 'F', '2012-03-15'),
    (1003, '1987-11-02', 'Robert', 'Johnson', 'M', '2015-07-30'),
    (1004, '1992-01-18', 'Emily', 'Davis', 'F', '2018-01-05'),
    (1005, '1980-12-09', 'Michael', 'Brown', 'M', '2008-11-21');

Import data using Flink SQL

  1. Start the Flink SQL Client from the bin directory.

    ./sql-client.sh
  2. Create the MySQL source table. The WITH clause configures the MySQL Change Data Capture (CDC) source. For all available options, see MySQL CDC connector options.

    CREATE TABLE employees_source (
        emp_no INT,
        birth_date DATE,
        first_name STRING,
        last_name STRING,
        gender STRING,
        hire_date DATE,
        PRIMARY KEY (`emp_no`) NOT ENFORCED
    ) WITH (
        'connector' = 'mysql-cdc',
        'hostname' = '127.0.0.1',
        'port' = '3306',
        'username' = 'root',
        'password' = '****',
        'database-name' = 'test',
        'table-name' = 'employees'
    );
  3. Create the SelectDB sink table. The WITH clause configures the Doris sink. For all available parameters, see Sink configuration parameters.

    CREATE TABLE employees_sink (
        emp_no       INT,
        birth_date   DATE,
        first_name   STRING,
        last_name    STRING,
        gender       STRING,
        hire_date    DATE
    )
    WITH (
      'connector' = 'doris',
      'fenodes' = 'selectdb-cn-****.selectdbfe.rds.aliyuncs.com:8080',
      'table.identifier' = 'test.employees',
      'username' = 'admin',
      'password' = '****'
    );
  4. Synchronize data from MySQL to SelectDB.

    INSERT INTO employees_sink SELECT * FROM employees_source;
  5. Verify the import. Connect to SelectDB and run:

    SELECT * FROM test.employees;

Import data using Flink CDC

Important

Realtime Compute for Apache Flink does not support JAR jobs. Use YAML jobs for CDC 3.0 instead.

Flink CDC synchronizes an entire database from a source to SelectDB in one command. Run the following from your Flink installation directory:

<FLINK_HOME>/bin/flink run \
    -Dexecution.checkpointing.interval=10s \
    -Dparallelism.default=1 \
    -c org.apache.doris.flink.tools.cdc.CdcTools \
    lib/flink-doris-connector-1.16-1.5.2.jar \
    <mysql-sync-database|oracle-sync-database|postgres-sync-database|sqlserver-sync-database> \
    --database <selectdb-database-name> \
    [--job-name <flink-job-name>] \
    [--table-prefix <selectdb-table-prefix>] \
    [--table-suffix <selectdb-table-suffix>] \
    [--including-tables <mysql-table-name|name-regular-expr>] \
    [--excluding-tables <mysql-table-name|name-regular-expr>] \
    --mysql-conf <mysql-cdc-source-conf> [--mysql-conf <mysql-cdc-source-conf> ...] \
    --oracle-conf <oracle-cdc-source-conf> [--oracle-conf <oracle-cdc-source-conf> ...] \
    --sink-conf <doris-sink-conf> [--sink-conf <doris-sink-conf> ...] \
    [--table-conf <selectdb-table-conf> [--table-conf <selectdb-table-conf> ...]]
Add the required CDC JAR (e.g., flink-sql-connector-mysql-cdc-${version}.jar) to $FLINK_HOME/lib before running.
Full database synchronization requires Flink 1.15 or later.

Parameters

ParameterDescription
execution.checkpointing.intervalFlink checkpoint interval. Controls data synchronization frequency. Use 10s.
parallelism.defaultParallelism degree for the Flink job. Higher values increase sync speed.
job-nameName of the Flink job.
databaseTarget database name in SelectDB.
table-prefixPrefix for SelectDB table names. Example: --table-prefix ods_.
table-suffixSuffix for SelectDB table names.
including-tablesTables to sync. Separate multiple tables with |. Regex supported. Example: table1|tbl.*.
excluding-tablesTables to exclude. Same format as including-tables.
mysql-confMySQL CDC source configuration. Required fields: hostname, username, password, database-name. See MySQL CDC connector.
oracle-confOracle CDC source configuration. Required fields: hostname, username, password, database-name, schema-name. See Oracle CDC connector.
sink-confDoris sink configuration. See Sink configuration parameters.
table-confSelectDB table properties, equivalent to the properties block in a CREATE TABLE statement.

Synchronization examples

MySQL synchronization example

<FLINK_HOME>/bin/flink run \
    -Dexecution.checkpointing.interval=10s \
    -Dparallelism.default=1 \
    -c org.apache.doris.flink.tools.cdc.CdcTools \
    lib/flink-doris-connector-1.16-1.5.2.jar \
    mysql-sync-database \
    --database test_db \
    --mysql-conf hostname=127.0.0.1 \
    --mysql-conf port=3306 \
    --mysql-conf username=root \
    --mysql-conf password="password" \
    --mysql-conf database-name=test \
    --including-tables "tbl1|test.*" \
    --sink-conf fenodes=selectdb-cn-****.selectdbfe.rds.aliyuncs.com:8080 \
    --sink-conf username=admin \
    --sink-conf password=****

Oracle synchronization example

<FLINK_HOME>/bin/flink run \
    -Dexecution.checkpointing.interval=10s \
    -Dparallelism.default=1 \
    -c org.apache.doris.flink.tools.cdc.CdcTools \
    lib/flink-doris-connector-1.16-1.5.2.jar \
    oracle-sync-database \
    --database test_db \
    --oracle-conf hostname=127.0.0.1 \
    --oracle-conf port=1521 \
    --oracle-conf username=admin \
    --oracle-conf password="password" \
    --oracle-conf database-name=XE \
    --oracle-conf schema-name=ADMIN \
    --including-tables "tbl1|test.*" \
    --sink-conf fenodes=selectdb-cn-****.selectdbfe.rds.aliyuncs.com:8080 \
    --sink-conf username=admin \
    --sink-conf password=****

PostgreSQL synchronization example

<FLINK_HOME>/bin/flink run \
    -Dexecution.checkpointing.interval=10s \
    -Dparallelism.default=1 \
    -c org.apache.doris.flink.tools.cdc.CdcTools \
    lib/flink-doris-connector-1.16-1.5.2.jar \
    postgres-sync-database \
    --database db1 \
    --postgres-conf hostname=127.0.0.1 \
    --postgres-conf port=5432 \
    --postgres-conf username=postgres \
    --postgres-conf password="123456" \
    --postgres-conf database-name=postgres \
    --postgres-conf schema-name=public \
    --postgres-conf slot.name=test \
    --postgres-conf decoding.plugin.name=pgoutput \
    --including-tables "tbl1|test.*" \
    --sink-conf fenodes=selectdb-cn-****.selectdbfe.rds.aliyuncs.com:8080 \
    --sink-conf username=admin \
    --sink-conf password=****

SQL Server synchronization example

<FLINK_HOME>/bin/flink run \
    -Dexecution.checkpointing.interval=10s \
    -Dparallelism.default=1 \
    -c org.apache.doris.flink.tools.cdc.CdcTools \
    lib/flink-doris-connector-1.16-1.5.2.jar \
    sqlserver-sync-database \
    --database db1 \
    --sqlserver-conf hostname=127.0.0.1 \
    --sqlserver-conf port=1433 \
    --sqlserver-conf username=sa \
    --sqlserver-conf password="123456" \
    --sqlserver-conf database-name=CDC_DB \
    --sqlserver-conf schema-name=dbo \
    --including-tables "tbl1|test.*" \
    --sink-conf fenodes=selectdb-cn-****.selectdbfe.rds.aliyuncs.com:8080 \
    --sink-conf username=admin \
    --sink-conf password=****

Import data using the DataStream API

  1. Add the required Maven dependencies to your pom.xml.

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <scala.version>2.12</scala.version>
        <java.version>1.8</java.version>
        <flink.version>1.16.3</flink.version>
        <fastjson.version>1.2.62</fastjson.version>
        <scope.mode>compile</scope.mode>
    </properties>
    <dependencies>
        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>28.1-jre</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.14.0</version>
        </dependency>
        <!-- Flink Doris Connector -->
        <dependency>
            <groupId>org.apache.doris</groupId>
            <artifactId>flink-doris-connector-1.16</artifactId>
            <version>1.5.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.flink</groupId>
            <artifactId>flink-table-api-scala-bridge_${scala.version}</artifactId>
            <version>${flink.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.flink</groupId>
            <artifactId>flink-table-planner_${scala.version}</artifactId>
            <version>${flink.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.flink</groupId>
            <artifactId>flink-streaming-scala_${scala.version}</artifactId>
            <version>${flink.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.flink</groupId>
            <artifactId>flink-clients</artifactId>
            <version>${flink.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.flink</groupId>
            <artifactId>flink-connector-jdbc</artifactId>
            <version>${flink.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.flink</groupId>
            <artifactId>flink-connector-kafka</artifactId>
            <version>${flink.version}</version>
        </dependency>
        <dependency>
            <groupId>com.ververica</groupId>
            <artifactId>flink-sql-connector-mysql-cdc</artifactId>
            <version>2.4.2</version>
            <exclusions>
                <exclusion>
                    <artifactId>flink-shaded-guava</artifactId>
                    <groupId>org.apache.flink</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.apache.flink</groupId>
            <artifactId>flink-runtime-web</artifactId>
            <version>${flink.version}</version>
        </dependency>
    </dependencies>
  2. Write the job code. The MySQL source parameters and SelectDB sink parameters correspond to the configurations used in the Flink SQL example. For MySQL source options, see MySQL CDC connector options. For sink options, see Sink configuration parameters.

    package org.example;
    
    import com.ververica.cdc.connectors.mysql.source.MySqlSource;
    import com.ververica.cdc.connectors.mysql.table.StartupOptions;
    import com.ververica.cdc.connectors.shaded.org.apache.kafka.connect.json.JsonConverterConfig;
    import com.ververica.cdc.debezium.JsonDebeziumDeserializationSchema;
    
    import org.apache.doris.flink.cfg.DorisExecutionOptions;
    import org.apache.doris.flink.cfg.DorisOptions;
    import org.apache.doris.flink.sink.DorisSink;
    import org.apache.doris.flink.sink.writer.serializer.JsonDebeziumSchemaSerializer;
    import org.apache.doris.flink.tools.cdc.mysql.DateToStringConverter;
    import org.apache.flink.api.common.eventtime.WatermarkStrategy;
    import org.apache.flink.streaming.api.datastream.DataStreamSource;
    import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
    
    import java.util.HashMap;
    import java.util.Map;
    import java.util.Properties;
    
    public class Main {
        public static void main(String[] args) throws Exception {
            StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
            env.setParallelism(1);
            env.enableCheckpointing(10000);
    
            Map<String, Object> customConverterConfigs = new HashMap<>();
            customConverterConfigs.put(JsonConverterConfig.DECIMAL_FORMAT_CONFIG, "numeric");
            JsonDebeziumDeserializationSchema schema =
                    new JsonDebeziumDeserializationSchema(false, customConverterConfigs);
    
            // Configure the MySQL source
            MySqlSource<String> mySqlSource = MySqlSource.<String>builder()
                    .hostname("rm-xxx.mysql.rds.aliyuncs***")
                    .port(3306)
                    .startupOptions(StartupOptions.initial())
                    .databaseList("db_test")
                    .tableList("db_test.employees")
                    .username("root")
                    .password("test_123")
                    .debeziumProperties(DateToStringConverter.DEFAULT_PROPS)
                    .deserializer(schema)
                    .serverTimeZone("Asia/Shanghai")
                    .build();
    
            // Configure the SelectDB sink
            DorisSink.Builder<String> sinkBuilder = DorisSink.builder();
            DorisOptions.Builder dorisBuilder = DorisOptions.builder();
            dorisBuilder.setFenodes("selectdb-cn-xxx-public.selectdbfe.rds.aliyunc****:8080")
                    .setTableIdentifier("db_test.employees")
                    .setUsername("admin")
                    .setPassword("test_123");
            DorisOptions dorisOptions = dorisBuilder.build();
    
            // Configure Stream Load parameters
            Properties properties = new Properties();
            properties.setProperty("format", "json");
            properties.setProperty("read_json_by_line", "true");
            DorisExecutionOptions.Builder executionBuilder = DorisExecutionOptions.builder();
            executionBuilder.setStreamLoadProp(properties);
    
            sinkBuilder.setDorisExecutionOptions(executionBuilder.build())
                    .setSerializer(JsonDebeziumSchemaSerializer.builder().setDorisOptions(dorisOptions).build())
                    .setDorisOptions(dorisOptions);
    
            DataStreamSource<String> dataStreamSource = env.fromSource(mySqlSource, WatermarkStrategy.noWatermarks(), "MySQL Source");
            dataStreamSource.sinkTo(sinkBuilder.build());
            env.execute("MySQL to SelectDB");
        }
    }

Sink configuration parameters

Get the fenodes and jdbc-url values from Instance Details > Network Information in the ApsaraDB for SelectDB console.

ParameterDefaultRequiredDescription
fenodesNoneYesVPC endpoint or public endpoint plus HTTP port. Example: selectdb-cn-4xl3jv1****.selectdbfe.rds.aliyuncs.com:8080.
table.identifierNoneYesDatabase and table name. Example: test_db.test_table.
usernameNoneYesSelectDB username.
passwordNoneYesSelectDB password.
jdbc-urlNoneNoJDBC connection URL using the MySQL port. Example: jdbc:mysql://selectdb-cn-4xl3jv1****.selectdbfe.rds.aliyuncs.com:9030.
auto-redirecttrueNoRoutes Stream Load requests through the frontend (FE), so backend (BE) addresses are not required explicitly.
doris.request.retries3NoNumber of retries for requests to SelectDB.
doris.request.connect.timeout30sNoConnection timeout for requests to SelectDB.
doris.request.read.timeout30sNoRead timeout for requests to SelectDB.
sink.label-prefix""YesLabel prefix for Stream Load imports. Must be globally unique in two-phase commit (2PC) scenarios to guarantee Exactly-Once Semantics (EOS).
sink.propertiesNoneNoStream Load import parameters. For CSV: sink.properties.format='csv', sink.properties.column_separator=',', sink.properties.line_delimiter='\n'. For JSON: sink.properties.format='json'. See Stream Load.
sink.buffer-size1048576NoWrite buffer size in bytes. Keep the default (1 MB).
sink.buffer-count3NoNumber of write buffers. Keep the default.
sink.max-retries3NoMaximum retries after a commit failure.
sink.use-cachefalseNoUses a memory cache for recovery during exceptions. When enabled, the cache retains data from the checkpoint period.
sink.enable-deletetrueNoSyncs delete events. Supported only with the Unique Key model.
sink.enable-2pctrueNoEnables two-phase commit (2PC) to guarantee EOS.
sink.enable.batch-modefalseNoWrites in batch mode, controlled by sink.buffer-flush.* parameters rather than checkpoints. EOS is not guaranteed; use the Unique Key model for idempotent writes.
sink.flush.queue-size2NoCache queue size in batch mode.
sink.buffer-flush.max-rows50000NoMaximum rows per batch in batch mode.
sink.buffer-flush.max-bytes10MBNoMaximum bytes per batch in batch mode.
sink.buffer-flush.interval10sNoAsync flush interval in batch mode. Minimum: 1s.
sink.ignore.update-beforetrueNoIgnores update-before events.

Advanced usage

Update partial columns

Use sink.properties.partial_columns = 'true' to update only a subset of columns in an existing row.

-- Enable checkpointing
SET 'execution.checkpointing.interval' = '10s';

CREATE TABLE cdc_mysql_source (
   id INT,
   name STRING,
   bank STRING,
   age INT,
   PRIMARY KEY (id) NOT ENFORCED
) WITH (
 'connector' = 'mysql-cdc',
 'hostname' = '127.0.0.1',
 'port' = '3306',
 'username' = 'root',
 'password' = 'password',
 'database-name' = 'database',
 'table-name' = 'table'
);

CREATE TABLE selectdb_sink (
    id INT,
    name STRING,
    bank STRING,
    age INT
)
WITH (
  'connector' = 'doris',
  'fenodes' = 'selectdb-cn-****.selectdbfe.rds.aliyuncs.com:8080',
  'table.identifier' = 'database.table',
  'username' = 'admin',
  'password' = '****',
  'sink.properties.format' = 'json',
  'sink.properties.read_json_by_line' = 'true',
  'sink.properties.columns' = 'id,name,bank,age',
  'sink.properties.partial_columns' = 'true'  -- Enable partial column updates
);

INSERT INTO selectdb_sink SELECT id, name, bank, age FROM cdc_mysql_source;

Delete rows based on a Kafka field

In a CDC source, the Doris sink uses RowKind to identify delete events automatically. In a Kafka source, there is no RowKind, so you must map a message field to the hidden column __DORIS_DELETE_SIGN__ to trigger deletions.

-- Example Kafka message: {"op_type":"delete","data":{"id":1,"name":"zhangsan"}}
CREATE TABLE KAFKA_SOURCE(
  data STRING,
  op_type STRING
) WITH (
  'connector' = 'kafka',
  ...
);

CREATE TABLE SELECTDB_SINK(
  id INT,
  name STRING,
  __DORIS_DELETE_SIGN__ INT
) WITH (
  'connector' = 'doris',
  'fenodes' = 'selectdb-cn-****.selectdbfe.rds.aliyuncs.com:8080',
  'table.identifier' = 'db.table',
  'username' = 'admin',
  'password' = '****',
  'sink.enable-delete' = 'false',                                    -- Do not use RowKind for delete detection
  'sink.properties.columns' = 'id, name, __DORIS_DELETE_SIGN__'     -- Specify columns explicitly
);

INSERT INTO SELECTDB_SINK
SELECT json_value(data,'$.id') as id,
       json_value(data,'$.name') as name,
       if(op_type='delete', 1, 0) as __DORIS_DELETE_SIGN__
FROM KAFKA_SOURCE;

Troubleshooting

How do I write BITMAP data?

Map the source integer column to a BITMAP column using to_bitmap() in sink.properties.columns:

CREATE TABLE bitmap_sink (
  dt INT,
  page STRING,
  user_id INT
)
WITH (
  'connector' = 'doris',
  'fenodes' = 'selectdb-cn-****.selectdbfe.rds.aliyuncs.com:8080',
  'table.identifier' = 'test.bitmap_test',
  'username' = 'admin',
  'password' = '****',
  'sink.label-prefix' = 'selectdb_label',
  'sink.properties.columns' = 'dt,page,user_id,user_id=to_bitmap(user_id)'
);

`Label[label_0_1] has already been used` error

Cause: In an Exactly-Once scenario, the Flink job was not restarted from a checkpoint or savepoint, causing a duplicate label.

Solution: Restart the job from the latest checkpoint or savepoint. If Exactly-Once is not required, either disable 2PC (sink.enable-2pc=false) or change sink.label-prefix to a unique value.

`transaction[19650] not found` error

Cause: The transaction recorded in the checkpoint expired on the SelectDB side before it could be committed. The job cannot restart from that checkpoint.

Solution: Extend the streaming_label_keep_max_second parameter in SelectDB (default: 12 hours) to prevent future expiration.

`current running txns on db 10006 is 100, larger than limit 100` error

Cause: Either the number of concurrent import jobs for the same database exceeds 100, or frequently changing sink.label-prefix and restarting leaves many pre-committed transactions (in 2PC mode with the Duplicate or Aggregate Key model) that cannot be aborted.

Solution:

  • Increase max_running_txn_num_per_db in SelectDB. See max_running_txn_num_per_db.

  • Alternatively, switch to the Unique Key model and disable 2PC for idempotent writes.

`tablet writer write failed, tablet_id=190958, txn_id=3505530, err=-235` error

Cause: This occurs with connector versions before 1.1.0. High write frequency creates too many tablet versions.

Solution: Reduce the flush frequency by lowering sink.buffer-flush.max-bytes or increasing sink.buffer-flush.interval.

`TApplicationException: get_next failed: out of sequence response` error

Cause: Concurrency bug in the Thrift framework.

Solution: Upgrade to the latest connector version and a compatible Flink version.

`DorisRuntimeException: Fail to abort transaction` error

Cause: The transaction abort request failed. The HTTP status code indicates whether the failure is on the client or server side.

Solution: In the TaskManager logs, search for abort transaction response and check the HTTP status code to diagnose the issue.

How do I guarantee row order within a batch for a Unique Key table?

Add a sequence column to the sink table. See Specifying a sequence column for merge.

Data is not being written, but the Flink job shows no errors

Cause: From connector version 1.1.0 onward, writes are checkpoint-driven. Before 1.1.0, writes were data-driven and did not require checkpoints.

Solution: Enable checkpointing in your Flink job to flush data.

How do I skip dirty data during import?

To avoid job retries caused by dirty data (field format or length issues), either disable Stream Load strict mode (strict_mode=false,max_filter_ratio=1) or filter the data before it reaches the sink operator.

How must source and SelectDB table schemas correspond?

Source table columns and types must match the Flink SQL table definition, and the Flink SQL table definition must match the SelectDB table. Both mappings must be consistent for the import to succeed.

What's next