Connect with R2DBC

R2DBC (Reactive Relational Database Connectivity) is a specification and set of APIs for connecting to relational databases from Java and other JVM languages. The SingleStore R2DBC connector ("the connector") is a non-blocking, asynchronous Java client that enables reactive Java applications to connect to SingleStore using the R2DBC specification. Instead of the traditional JDBC "one thread per blocking query" model, R2DBC uses asynchronous I/O and reactive streams (for example, Publisher, Flux, and Mono) to integrate seamlessly with reactive frameworks, such as Spring WebFlux and Project Reactor.

Driver Compatibility

  • Java 8+ JDK

  • SingleStore version 9.0+

Install the SingleStore R2DBC Connector

To install the connector using Maven, include the following dependency in the pom.xml file of your project. Replace x.x.x with the connector version you want to use.

<dependency>
<groupId>com.singlestore</groupId>
<artifactId>r2dbc-singlestore</artifactId>
<version>x.x.x</version>
</dependency>

Note

To find the latest version of the driver, refer to the R2DBC Driver for SingleStore Maven repository.

Use the SingleStore R2DBC Connector

Create a ConnectionFactory to configure the connection to your SingleStore deployment. Use either of the following methods:

  • Builder API: Use SingleStoreConnectionConfiguration and SingleStoreConnectionFactory for an explicit, type-safe configuration. For example:

    import com.singlestore.r2dbc.SingleStoreConnectionConfiguration;
    import com.singlestore.r2dbc.SingleStoreConnectionFactory;
    import io.r2dbc.spi.ConnectionFactory;
    SingleStoreConnectionConfiguration conf =
    SingleStoreConnectionConfiguration.builder()
    .host("<host>")
    .port(<port>)
    .username("<username>")
    .password("<password>")
    .database("<database>")
    .build();
    // Implementation of io.r2dbc.spi.ConnectionFactory
    ConnectionFactory factory = new SingleStoreConnectionFactory(conf);
  • Connection URL: Use the standard SPI (Service Provider Interface) factory lookup and a R2DBC URL. The connection string must have the following format:

    r2dbc:singlestore:[sequential:|loadbalancing:]//<username>:<password>@<host>:<port>/[database][?connection_options=value] 

    For example:

    import io.r2dbc.spi.ConnectionFactories;
    import io.r2dbc.spi.ConnectionFactory;
    ConnectionFactory factory = ConnectionFactories.get("r2dbc:singlestore://s2user:p455w04d@svchost:3306/dbTest");

Refer to Connection Options for the options supported in the connection configuration.

Failover and Load-Balancing Modes

Failover occurs when the connection to the primary host becomes unavailable and the connector tries reconnecting to another host. During failover, the failed host is blacklisted for 60 seconds. The connector always attempts to connect to the non-blacklisted hosts first. However, if all the hosts are blacklisted, the connector can retry connecting to a blacklisted host before the 60-second cooldown.

Upon failover, the connector attempts the following:

  1. Connection recovery: The connector tries reconnecting to another host in the host list.

  2. Re-run the command (transaction): After a connection is re-established successfully, the connector attempts to re-run the affected query. After a successful reconnection:

    • If the connector can replay the query successfully, the query is run without returning any connectivity-related errors.

    • If the connector is unable to transparently handle the failure scenario, it returns an error.

The connector supports the following load-balancing modes:

  • sequential 

  • loadbalancing 

Load balancing enables the connector to distribute the load across multiple hosts. While initializing a connection or after a connection failure, the connector randomly selects a host and attempts to establish a connection. Once the connection is established, all the subsequent queries are run on this host until the connection is closed or fails.

Refer to the SingleStore R2DBC Connector GitHub repository for more information.

Connection Options

Option

Description

Default Value

host

Comma-separated list of endpoints or IP addresses of the SingleStore deployment. If the first host is unreachable, the connector uses the next specified host, and so on.

This option is non-operational if the socket option is set.

port

Port of the SingleStore deployment. 

3306

username

Username of the SingleStore database user with which to connect.

password

Password for the SingleStore database user.

database

Name of the SingleStore database to connect with.

connectTimeout

Specifies the connection timeout value (in seconds). Upon timeout, attempts to establish a connection to the current host are aborted.

10 (seconds)

tcpKeepAlive

Specifies whether the underlying network connection uses TCP keepalive probes. If enabled, idle TCP connections remain active. 

FALSE

tcpAbortiveClose

If enabled, resets TCP connections using an abortive (or hard) close instead of an orderly (graceful) close.

This option is useful in environments where connections are opened and closed in rapid succession, where new sockets may eventually fail to be created because all local ephemeral ports are consumed by TCP connections in the TCP_WAIT state.

FALSE

socket

Enables the use of a Unix domain socket for faster database connections where the database is locally deployed.

allowMultiQueries

Enables the connector to submit multiple queries in a single call.

Because it allows for SQL injection, this may pose a security risk. SingleStore does not recommend enabling this option.

FALSE

connectionAttributes

Specifies additional client information to send to the database. This enables the database to identify the client or application associated with each connection.

Query the MV_CONNECTION_ATTRIBUTES information schema view for this information.

sessionVariables

Specifies the session variables to set upon a successful connection.

tlsProtocol

Force enables TLS/SSL protocol for the connection, specified as a comma-separated list.

Java default

serverSslCert

Use this option to specify the server's certificate in DER format or specify the server's CA certificate. This allows the connection to trust a self-signed certificate.

You can specify the server certificate in one of the following formats:

  • Specify the complete path: serverSslCert=/full_path/cert.pem

  • Specify a relative path: serverSslCert=classpath:relative/cert.pem

  • Specify a DER-encoded certificate string: "------BEGIN CERTIFICATE-----"

clientSslCert

Use this option to specify the client's certificate in DER format. Use this option exclusively for mutual authentication. 

You can specify the client certificate in one of the following formats:

  • Specify the complete path: clientSslCert=/full_path/cert.pem

  • Specify a relative path: clientSslCert=classpath:relative/cert.pem

  • Specify a DER-encoded certificate string: "------BEGIN CERTIFICATE-----"

clientSslKey

The client's private key path for mutual authentication.

clientSslPassword

Password of the client private key.

sslMode

Specifies the SSL/TLS mode. It can have one of the following values:

  • DISABLE: Disable the use of SSL/TLS.

  • TRUST: Use SSL/TLS only for encryption, and do not perform certificate or hostname verification. SingleStore does not recommend this mode for production environments.

  • VERIFY-CA: Use SSL/TLS for encryption and perform certificate verification, but do not perform hostname verification.

  • VERIFY-FULL: Use SSL/TLS for encryption, certificate verification, and hostname verification.

  • TUNNEL: Connect using a pre-established SSL tunnel. Refer to sslContextBuilderCustomizer and sslTunnelDisableHostVerification options for related information.

DISABLE

sslContextBuilderCustomizer

Enables customization of SSL context builder.

sslTunnelDisableHostVerification

Disables hostname verification during SSLHandshake when sslMode is set to TUNNEL.

useServerPrepStmts

Enables using prepared statements. Prepared statements are pre-compiled on the server-side before executing. Applications that use the same queries repeatedly can enable this option. In general, it's preferable to leave this parameter as FALSE, because SingleStore has wider support of queries in text protocol and has internal mechanisms of query parameterization.

FALSE

prepareCacheSize

Specifies the prepared statement cache size (number of saved statements).

If useServerPrepStmts is set to TRUE, it caches prepared statements in a LRU cache to avoid preparing the query again, which allows the server to avoid re-parsing a query. For subsequent runs of a command, only the prepared identifier and parameters (if any) are sent to the server.

256

pamOtherPwd

Specifies an additional password for PAM authentication in multi-step authentication. If multiple passwords are used, the value must be URL-encoded.

autoCommit

Sets the autocommit value on connection initialization.

loopResources

Enables sharing a Netty EventLoopGroup among multiple asynchronous libraries or frameworks.

skipPostCommands

Specifies whether initialization commands sent after a connection is established are skipped. This helps avoid unnecessary commands upon connection creation and prevents session pinning when using an RDV proxy. 

The connector expects the server to meet the following conditions:

  • Connection exchanges use UTF-8 (mb3/mb4).

  • Autocommit is enabled.

enableExtendedDataTypes

Enables extended data types, by enabling the enable_extended_types_metadata engine variable, that allow the connector to support extended data types, such as VECTOR and BSON.

Example

The following example connects to a SingleStore deployment, inserts data into a table, and then queries the data.

  1. Create a Maven project.

    mvn archetype:generate \
    -DgroupId=com.example \
    -DartifactId=singlestore-r2dbc-demo \
    -DarchetypeArtifactId=maven-archetype-quickstart \
    -DinteractiveMode=false
  2. Add the required dependencies and plugins to the pom.xml file of the project. This example includes the following:

    <dependencies>
    <dependency>
    <groupId>com.singlestore</groupId>
    <artifactId>r2dbc-singlestore</artifactId>
    <version>1.0.0</version>
    </dependency>
    <!-- Reactor, used by R2DBC APIs -->
    <dependency>
    <groupId>io.projectreactor</groupId>
    <artifactId>reactor-core</artifactId>
    <version>3.6.5</version>
    </dependency>
    <!-- Simple logging (optional but helpful) -->
    <dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-simple</artifactId>
    <version>2.0.9</version>
    </dependency>
    <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>3.8.1</version>
    <scope>test</scope>
    </dependency>
    </dependencies>
    <build>
    <plugins>
    <!-- Compiler plugin (already controlled by properties) -->
    <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.11.0</version>
    </plugin>
    <!-- To run the app via `mvn exec:java` -->
    <plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>exec-maven-plugin</artifactId>
    <version>3.1.0</version>
    <configuration>
    <mainClass>com.example.R2dbcExample</mainClass>
    </configuration>
    </plugin>
    </plugins>
    </build>
  3. Create a main class. This example builds a SingleStoreConnectionConfiguration and SingleStoreConnectionFactory using the connector’s builder API.

    package com.example;
    import com.singlestore.r2dbc.SingleStoreConnectionConfiguration;
    import com.singlestore.r2dbc.SingleStoreConnectionFactory;
    import io.r2dbc.spi.Connection;
    import io.r2dbc.spi.ConnectionFactory;
    import reactor.core.publisher.Flux;
    import reactor.core.publisher.Mono;
    public class R2dbcExample {
    public static void main(String[] args) {
    // 1) Configure connection (update these with your actual values)
    SingleStoreConnectionConfiguration conf =
    SingleStoreConnectionConfiguration.builder()
    .host("svchost")
    .port(3306)
    .username("s2user")
    .password("passkey")
    .database("dbTest")
    .build(); // builder style
    // 2) Create a ConnectionFactory
    ConnectionFactory factory = new SingleStoreConnectionFactory(conf);
    // 3) Use R2DBC reactively: create table, insert, and query
    Mono.from(factory.create())
    .flatMapMany(connection ->
    // use a helper that ensures the connection is closed
    runExampleQueries(connection)
    .doFinally(signal -> Mono.from(connection.close()).subscribe())
    )
    .doOnNext(rowString -> System.out.println("Row: " + rowString))
    .blockLast(); // block to keep the JVM alive for this simple demo
    }
    private static Flux<String> runExampleQueries(Connection connection) {
    // Simple schema + data
    String createTableSql =
    "CREATE TABLE IF NOT EXISTS demo_r2dbc (" +
    " id INT PRIMARY KEY, " +
    " name VARCHAR(64)" +
    ")";
    String insertSql =
    "INSERT INTO demo_r2dbc (id, name) VALUES (1, 'Alice'), (2, 'John'), (3, 'Jane') " +
    "ON DUPLICATE KEY UPDATE name = VALUES(name)";
    String selectSql = "SELECT id, name FROM demo_r2dbc";
    // Execute steps in sequence:
    return Mono.from(
    connection.createStatement(createTableSql)
    .execute()
    )
    .flatMapMany(result -> result.getRowsUpdated())
    .thenMany(
    Mono.from(
    connection.createStatement(insertSql)
    .execute()
    ).flatMapMany(r -> r.getRowsUpdated())
    )
    .thenMany(
    Mono.from(
    connection.createStatement(selectSql)
    .execute()
    )
    .flatMapMany(result ->
    result.map((row, meta) -> {
    Integer id = row.get("id", Integer.class);
    String name = row.get("name", String.class);
    return "id=" + id + ", name=" + name;
    })
    )
    );
    }
    }

    Alternatively, you can construct the ConnectionFactory with a R2DBC URL instead of the builder. For example:

    ConnectionFactory factory =
    ConnectionFactories.get(
    "r2dbc:singlestore://s2user:password@svchost:3306/dbtest"
    );
  4. Build and run the application. Run the following command from the project root directory.

    mvn -q clean compile exec:java
    Row: id=1, name=Alice
    Row: id=2, name=John
    Row: id=3, name=Jane

    A similar output indicates that the application ran as expected.

Last modified: January 30, 2026

Was this article helpful?

Verification instructions

Note: You must install cosign to verify the authenticity of the SingleStore file.

Use the following steps to verify the authenticity of singlestoredb-server, singlestoredb-toolbox, singlestoredb-studio, and singlestore-client SingleStore files that have been downloaded.

You may perform the following steps on any computer that can run cosign, such as the main deployment host of the cluster.

  1. (Optional) Run the following command to view the associated signature files.

    curl undefined
  2. Download the signature file from the SingleStore release server.

    • Option 1: Click the Download Signature button next to the SingleStore file.

    • Option 2: Copy and paste the following URL into the address bar of your browser and save the signature file.

    • Option 3: Run the following command to download the signature file.

      curl -O undefined
  3. After the signature file has been downloaded, run the following command to verify the authenticity of the SingleStore file.

    echo -n undefined |
    cosign verify-blob --certificate-oidc-issuer https://oidc.eks.us-east-1.amazonaws.com/id/CCDCDBA1379A5596AB5B2E46DCA385BC \
    --certificate-identity https://kubernetes.io/namespaces/freya-production/serviceaccounts/job-worker \
    --bundle undefined \
    --new-bundle-format -
    Verified OK

Try Out This Notebook to See What’s Possible in SingleStore

Get access to other groundbreaking datasets and engage with our community for expert advice.