Remote JDBC is a Type-3 JDBC driver for Java 11+.
It allows a Java application to use the standard java.sql API while the
actual JDBC connection and JDBC resources are maintained on a remote server.
The client communicates with the server over HTTP(S) using a compact binary
protocol based on JVx UniversalSerializer.
The database-specific JDBC driver is installed on the server. The client does not need the JDBC driver of the target database.
Remote JDBC is useful when a client cannot or should not connect directly to a database, for example:
- the database is only reachable from a protected server network
- a database should not be exposed to client networks
- an application server should own the database credentials
- existing Java applications should continue to use the standard JDBC API
- tools such as DBeaver should access a database through a JDBC-over-HTTP endpoint
No application-specific database API is required. Applications continue to
use java.sql.Connection, PreparedStatement, ResultSet, and the other
standard JDBC interfaces.
+------------------------+
| Java application |
| DBeaver / JDBC client |
+-----------+------------+
|
| jdbc:rjdbc:https://...
| HTTP POST
v
+------------------------+
| Remote JDBC client |
| JDBC Driver |
+-----------+------------+
|
| HTTP(S)
| binary protocol
v
+------------------------+
| Servlet container |
| JdbcServlet |
+-----------+------------+
|
| JDBC
v
+------------------------+
| Target database |
| + database JDBC driver |
+------------------------+
A remote JDBC Connection represents a server-side session. The session owns
the corresponding server-side JDBC connection and the JDBC resources created
from it.
- Standard
java.sql.Driver - Automatic driver registration through
META-INF/services/java.sql.Driver - JDBC URL prefix:
jdbc:rjdbc: - Java 11+
- Standard
DriverManagerintegration - Connection properties
Connection.isValid(...)- Connection/session lifecycle handling
The implementation provides remote representations for:
ConnectionStatementPreparedStatementCallableStatementResultSetResultSetMetaDataDatabaseMetaDataParameterMetaDataBlobClobNClobSQLXMLArrayStructRefRowIdSavepoint
The implementation uses concrete remote JDBC classes rather than Java dynamic proxies.
Unsupported JDBC operations are reported using JDBC exceptions such as
SQLFeatureNotSupportedException where appropriate.
Result sets use client-side caching and block fetching.
Instead of transferring an entire result set in one response, rows are transferred in blocks. This reduces network round trips and allows large result sets to be processed without one huge response.
The implementation covers, among other things:
next()previous()first()last()absolute()relative()beforeFirst()afterLast()- cursor-state methods
- column access by index and label
wasNull()- ResultSet metadata
- updateable result sets where supported by the underlying JDBC driver
The server limits a single remote fetch to 10,000 rows.
Supported functionality includes:
executeQueryexecuteUpdateexecute- generated keys where supported by the underlying driver
- fetch size
- max rows
- max field size
- query timeout
- warnings
- poolable state
- close-on-completion
- multiple results
- batch execution
- wrapper support
- parameter binding
- parameter metadata
- streams and readers
- LOB parameters
- large-update APIs where supported
Prepared batches are executed against the server-side JDBC connection.
The server limits a prepared batch to 10,000 entries.
Transactions belong to the individual remote session and therefore to the corresponding server-side JDBC connection.
connection.setAutoCommit(false);
try {
// JDBC operations...
connection.commit();
}
catch (SQLException e) {
connection.rollback();
throw e;
}Supported transaction functionality includes:
- auto-commit
- commit
- rollback
- transaction isolation
- read-only state
- savepoints
- rollback to savepoint
- release savepoint
The actual behavior ultimately depends on the target database and its JDBC driver.
Remote support is provided for:
BlobClobNClobSQLXML- binary streams
- character streams
- readers
- writers
CLOB prefetching can be configured on the server.
The default is:
clobPrefetchSize = 102400
The value is measured in characters, not bytes and not megabytes.
CLOB data exceeding the configured prefetch size is loaded on demand.
DatabaseMetaData and ResultSetMetaData are transferred over the remote
protocol.
The implementation covers a broad range of metadata operations, including:
- database/product information
- driver information
- JDBC capabilities
- tables
- columns
- primary keys
- indexes
- imported keys
- exported keys
- best-row identifiers
- version columns
- type information
- procedures
The project can be built with Apache Ant using:
build.xml
The JDBC driver service registration is located at:
src.jdbc/META-INF/services/java.sql.Driver
Deploy the server servlet to a servlet container such as Tomcat.
The servlet class is:
com.sibvisions.rjdbc.server.JdbcServlet
A minimal servlet mapping is:
<servlet>
<servlet-name>rjdbc</servlet-name>
<servlet-class>com.sibvisions.rjdbc.server.JdbcServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>rjdbc</servlet-name>
<url-pattern>/jdbc/*</url-pattern>
</servlet-mapping>The current server implementation uses the javax.servlet API.
The JDBC driver for the target database must be available to the server-side application.
For example:
Tomcat
|
+-- Remote JDBC servlet
|
+-- Oracle JDBC driver
The Oracle, PostgreSQL, MySQL, SQL Server, etc. JDBC driver is not needed by the Remote JDBC client merely to establish the remote connection.
For a production deployment, configure the database connection on the server:
<init-param>
<param-name>environment</param-name>
<param-value>production</param-value>
</init-param>
<init-param>
<param-name>jdbcUrl</param-name>
<param-value>jdbc:oracle:thin:@dbserver:1521/ORCL</param-value>
</init-param>
<init-param>
<param-name>jdbcUsername</param-name>
<param-value>application_user</param-value>
</init-param>
<init-param>
<param-name>jdbcPassword</param-name>
<param-value>change-me</param-value>
</init-param>
<init-param>
<param-name>token</param-name>
<param-value>change-me-to-a-strong-random-token</param-value>
</init-param>optional
<init-param>
<param-name>tokenManager</param-name>
<param-value>c.s.r.s.CustomTokenManager</param-value>
</init-param>Do not store real production credentials or tokens in source control.
try (Connection connection =
DriverManager.getConnection(
"jdbc:rjdbc:https://server.example/app/jdbc",
"user",
"password")) {
try (PreparedStatement statement =
connection.prepareStatement(
"select id, name from customer where id = ?")) {
statement.setInt(1, 42);
try (ResultSet resultSet = statement.executeQuery()) {
while (resultSet.next()) {
System.out.println(
resultSet.getInt("id") + " " +
resultSet.getString("name"));
}
}
}
}The driver is normally registered automatically through the Java service
provider mechanism. Class.forName(...) is therefore normally not required.
If explicit registration is required, the driver class is:
com.sibvisions.rjdbc.RemoteDriver
A Remote JDBC URL starts with:
jdbc:rjdbc:
Example:
jdbc:rjdbc:https://server.example/app/jdbc
The URL after jdbc:rjdbc: is the HTTP(S) endpoint of the Remote JDBC
servlet.
The target database JDBC URL is not appended to the Remote JDBC URL.
The target database URL is selected by the server:
- in production, from the server configuration
- in non-production environments, optionally from a client-supplied JDBC URL
that passes the server's
allowedJdbcUrlspolicy
Remote JDBC uses JDBC connection properties for remote-specific options.
For example, the authentication token is supplied as the token property
when token authentication is used.
A client must not assume that the username/password arguments of
DriverManager.getConnection(...) are database credentials in every server
configuration. In production the server owns the database credentials.
The server is exposed as:
com.sibvisions.rjdbc.server.JdbcServlet
Supported servlet initialization parameters are:
| Parameter | Default | Description |
|---|---|---|
environment |
development |
Server environment. production activates the production rules. |
allowedJdbcUrls |
empty | Allow-list for client-supplied JDBC URLs. |
jdbcUrl |
empty | Server-side JDBC URL. Required in production. |
jdbcUsername |
empty | Server-side JDBC username. Required in production. |
jdbcPassword |
empty | Server-side JDBC password. Required in production. |
token |
empty | Optional token configuration. In production a token must be configured and supplied by the client. |
tokenManager |
empty | Optional token manager (full class name). In production a token must be configured and supplied by the client. |
privateKey |
empty | Optional PKCS#12 key-store resource containing the server private key. Enables Remote JDBC protocol encryption. |
privateKeyPassword |
empty | Password used to open the PKCS#12 key store/private-key entry. |
privateKeyAlias |
empty | Optional private-key alias. If omitted, the first private-key entry is selected. |
idleTimeout |
1800000 |
Session idle timeout in milliseconds. 1800000 = 30 minutes. 0 disables expiration. |
clobPrefetchSize |
102400 |
Maximum CLOB prefetch size in characters. |
The unit is milliseconds.
Default:
1800000 ms = 30 minutes
Example:
<init-param>
<param-name>idleTimeout</param-name>
<param-value>1800000</param-value>
</init-param>A value of 0 disables idle expiration.
Active requests are protected from idle-session cleanup.
The value is a number of characters.
Default:
102400 characters
It is not a size in MB.
Development mode is useful when the client needs to select the target JDBC URL.
Example:
<init-param>
<param-name>environment</param-name>
<param-value>development</param-value>
</init-param>
<init-param>
<param-name>allowedJdbcUrls</param-name>
<param-value>jdbc:oracle:thin:@localhost:1521/XE</param-value>
</init-param>The client can then provide the allowed database JDBC URL.
Do not expose an unrestricted client-JDBC-URL configuration to untrusted networks.
Set:
<init-param>
<param-name>environment</param-name>
<param-value>production</param-value>
</init-param>Production mode requires:
- a server-side
jdbcUrl - a server-side
jdbcUsername - a server-side
jdbcPassword - a configured authentication
tokenor `tokenManager
The client cannot select the target JDBC URL in production.
Client JDBC URL, username, password and client JDBC properties are not used to override the server-side production database configuration.
The production connection therefore follows this model:
Remote JDBC client
|
| authentication token
v
Remote JDBC servlet
|
| fixed URL + fixed credentials
v
Target database
This is the recommended configuration when the Remote JDBC endpoint is used by untrusted or semi-trusted clients.
Remote JDBC provides two protocol-level security mechanisms:
- token authentication;
- optional application-level encryption.
They are separate mechanisms.
The server can be configured with:
<init-param>
<param-name>token</param-name>
<param-value>...</param-value>
</init-param>The client supplies the token using the JDBC connection property:
token
Token comparison uses a constant-time comparison.
In production, token authentication is mandatory. A production server without a configured token rejects connection initialization.
In non-production environments:
- if no token is configured, no token is required
- if a token is configured, a supplied token is checked
- an incorrect supplied token is rejected
Token authentication by itself does not encrypt HTTP traffic.
Therefore:
HTTP + token
provides authentication, but not transport confidentiality.
Use HTTPS when the HTTP connection itself must be protected.
Remote JDBC can additionally encrypt the protocol payload.
Configure the server with a PKCS#12 key store:
<init-param>
<param-name>privateKey</param-name>
<param-value>rjdbc-appserver.p12</param-value>
</init-param>
<init-param>
<param-name>privateKeyPassword</param-name>
<param-value>...</param-value>
</init-param>
<init-param>
<param-name>privateKeyAlias</param-name>
<param-value>rjdbc</param-value>
</init-param>The server loads a private key from the PKCS#12 key store.
The protocol security implementation uses:
- RSA-OAEP with SHA-256 for the handshake key
- AES-GCM for encrypted payloads
- HMAC-SHA-256 for direction-specific key derivation
- random nonces
- per-connection keys
- authenticated data containing the protocol version, session ID, sequence number and direction
The private key remains on the server.
The application-level protocol encryption protects the Remote JDBC payload. It is not TLS and does not turn an HTTP endpoint into an HTTPS endpoint.
For an Internet-facing deployment, HTTPS is strongly recommended.
Recommended architecture:
Remote JDBC client
|
| HTTPS
v
Reverse proxy / Tomcat
|
| Remote JDBC protocol
v
Database
HTTPS protects the HTTP transport itself, including the Remote JDBC binary payload, authentication token and other request data.
Protocol encryption can additionally be enabled when an independent application-level encryption boundary is desired.
The following are different:
| Configuration | Authentication | HTTP transport encryption | Remote protocol encryption |
|---|---|---|---|
| HTTP only | No | No | No |
| HTTP + token | Yes | No | No |
| HTTPS | Depends on deployment | Yes | No |
| HTTPS + token | Yes | Yes | No |
HTTPS + token + privateKey |
Yes | Yes | Yes |
For production deployments, HTTPS plus token authentication and a fixed server-side database configuration is the normal recommendation.
The server can restrict client-selected JDBC URLs with:
allowedJdbcUrls
It is a semicolon separated list with support for wildcard (*).
A client-supplied URL is accepted only when it matches the configured allow-list.
This is useful in development or controlled multi-database deployments.
For production, a fixed server-side jdbcUrl is preferable.
Do not use a broad allow-list as a substitute for authentication.
When a client-selected JDBC URL is used, the client configuration is used for the selected database connection.
When the server-side JDBC configuration is used, the server's
jdbcUsername and jdbcPassword are applied.
In production the server-side credentials are mandatory.
Each remote JDBC connection gets its own server-side session.
A session tracks server-side JDBC resources such as:
ConnectionStatementPreparedStatementCallableStatementResultSet- metadata objects
BlobClobNClobSQLXMLArrayStructRefRowIdSavepoint- executors
Session IDs are generated on the server.
Resources are released when the corresponding remote resource is closed and when the complete session is closed.
The server also cleans up tracked resources when:
- a session expires
- a connection/session is explicitly closed
- the servlet is destroyed
The default idle timeout is 30 minutes.
Remote JDBC uses HTTP POST with:
Content-Type: application/octet-stream
Accept: application/octet-stream
The payload is serialized using:
com.sibvisions.rad.remote.UniversalSerializer
The protocol represents remote JDBC resources using server-side IDs.
The logical request/response data contains fields such as:
id
sessionId
action
sql
value
values
result
rows
error
success
The protocol is intentionally small and keeps JDBC objects on the server instead of trying to serialize the complete JDBC object graph.
Remote JDBC exceptions are returned through the protocol and reconstructed on
the client as SQLException instances.
Where available, the implementation preserves:
- message
- SQL state
- vendor error code
- chained exceptions
Communication failures are converted into SQLException and the affected
remote session is treated as broken.
A session expiration is distinguished from a normal JDBC operation failure.
Remote JDBC itself is database-independent.
The target database JDBC driver is loaded on the server.
The server contains explicit driver initialization for commonly used JDBC URL prefixes, including:
- Oracle
- DB2
- IBM i / AS/400
- Derby
- jTDS SQL Server
- Microsoft SQL Server
- MySQL
- PostgreSQL
- EDB
- HSQLDB
- SQLite
- H2
- MariaDB
For other JDBC drivers, the server can use Java's ServiceLoader mechanism.
The actual supported functionality is ultimately determined by the JDBC driver and database installed on the server.
Remote JDBC is suitable for servlet containers such as Tomcat.
The current servlet implementation uses:
javax.servlet.*
Therefore the current source targets the javax.servlet API.
If deploying to a Jakarta Servlet-only container, use built jakarta binary.
For a Tomcat deployment, the important pieces are:
Tomcat
|
+-- Remote JDBC web application
| |
| +-- JdbcServlet
| +-- Remote JDBC server classes
|
+-- JVx serialization dependency
|
+-- target database JDBC driver
The database must be reachable from the Tomcat/server host, not from the Remote JDBC client.
Remote JDBC can be used by JDBC clients that support custom JDBC drivers.
The important distinction is:
DBeaver
|
| Remote JDBC driver
|
v
Remote JDBC servlet
|
| Oracle/PostgreSQL/etc. JDBC driver
|
v
Database
DBeaver does not need direct network access to the database.
It needs network access to the Remote JDBC HTTP(S) endpoint.
For an Oracle database, for example, the Oracle JDBC driver belongs on the
Remote JDBC server. The DBeaver client uses the Remote JDBC driver and the
jdbc:rjdbc: URL.
Check the JDBC URL.
The client URL must start with:
jdbc:rjdbc:
For example:
jdbc:rjdbc:https://server.example/app/jdbc
Do not configure the Remote JDBC client with the target database URL:
jdbc:oracle:thin:@localhost:1521/XE
That is a server-side database URL.
If the error occurs on the server side, verify that the target JDBC driver is installed and visible to the server class loader.
Check:
- the database JDBC JAR is installed on the server
- the JAR is visible to the application/server class loader
- the JDBC URL uses the correct database-specific prefix
- the corresponding JDBC driver class is available
For Oracle, for example:
jdbc:oracle:
causes the server to initialize:
oracle.jdbc.OracleDriver
Verify that all production settings are present:
environment=production
jdbcUrl=<server-side JDBC URL>
jdbcUsername=<server-side DB user>
jdbcPassword=<server-side DB password>
token=<strong token> or tokenManager=<full qualfied class name>
The client must provide the configured Remote JDBC token.
If the client is allowed to select the database URL, verify:
allowedJdbcUrls
The supplied URL must match the configured allow-list.
For production, do not expect the client JDBC URL to be accepted. Production
uses the server-side jdbcUrl.
Check:
idleTimeout
The unit is milliseconds.
For example:
1800000 = 30 minutes
3600000 = 60 minutes
0 = disabled
Check:
clobPrefetchSize
The value is measured in characters.
Default:
102400 characters
Larger CLOB values are fetched on demand.
Remote JDBC adds network latency to JDBC operations.
Applications should therefore avoid unnecessary request/response cycles.
Important factors include:
- network latency
- database latency
- ResultSet fetch size
- number of JDBC calls
- batch size
- LOB usage
- database driver behavior
Result sets are fetched in blocks and the server limits one fetch operation to 10000 rows.
Prepared batches are limited to 10000 entries.
For high-latency networks, batching and appropriate fetch sizes can have a significant impact on performance.
The project contains an extensive JDBC regression test suite.
Covered areas include:
- driver contract
- connection contract
- connection lifecycle
isValid- Statement lifecycle
- PreparedStatement lifecycle
- CallableStatement
- ResultSet navigation
- empty ResultSets
- ResultSet cursor state
- updatable ResultSets
- ResultSet metadata
- DatabaseMetaData
- NULL handling
- JDBC type conversions
BigDecimal- batch processing
- LOBs
- NClob
- SQLXML
- wrappers
- resource lifecycle
- session isolation
- concurrent independent connections
- concurrent metadata operations
- concurrent connection state changes
- streaming
- exception transparency
The tests compare remote JDBC behavior with normal JDBC behavior where that is meaningful and also verify Remote JDBC-specific session and lifecycle contracts.
src.jdbc/
com/sibvisions/rjdbc/
Remote JDBC client
src.server/
com/sibvisions/rjdbc/server/
Remote JDBC servlet/server
test/
com/sibvisions/rjdbc/
JDBC contract and regression tests
security/
Security-related helpers
The server-side delegate classes isolate JDBC resource handling from the HTTP transport.
The project requires:
-
Java 11 or newer
-
JVx serialization support containing
com.sibvisions.rad.remote.UniversalSerializer<dependency> <groupId>com.sibvisions.jvx</groupId> <artifactId>jvxserialize</artifactId> <version>3.5.2</version> </dependency> -
Servlet API on the server side
The current servlet implementation uses:
javax.servlet-api
The target database JDBC driver is required on the server, not on the Remote JDBC client.
Remote JDBC focuses on:
-
Standard JDBC API
Applications use normal
java.sqlinterfaces. -
Small remote protocol
JDBC resources are represented by IDs and remote method calls rather than by a large custom object model.
-
Server-side JDBC execution
Database-specific JDBC drivers remain on the server.
-
Session isolation
Each remote connection owns its own JDBC session and resources.
-
Block-based ResultSet fetching
Large result sets do not need to be transferred in a single response.
-
Explicit resource lifecycle
Remote resources are tracked and released on both client and server.
-
Database independence
Remote JDBC itself does not depend on Oracle, PostgreSQL, MySQL, or another specific database.
Remote JDBC aims for broad practical JDBC compatibility. It is not a claim of complete JDBC 4.x/4.3 compliance.
Important limitations:
Driver.jdbcCompliant()returnsfalse- behavior depends on the JDBC driver and database used on the server
- network latency is inherent in remote JDBC
- some JDBC operations are unsupported or depend on the underlying driver
- the current servlet implementation uses
javax.servlet - the protocol uses JVx serialization
- performance depends on fetch sizes, database latency, network latency and server-side JDBC driver behavior
The project should therefore be evaluated against the specific JDBC driver and database features required by an application.
For a production deployment:
- Use HTTPS
- Use
environment=production - Configure a fixed server-side
jdbcUrl - Configure server-side
jdbcUsername - Configure server-side
jdbcPassword - Configure a strong
tokenortokenManager - Keep the database credentials and token out of source control
- Restrict network access to the Remote JDBC endpoint
- Use least-privilege database credentials
- Do not expose unrestricted client JDBC URLs
- Protect the PKCS#12 private key if protocol encryption is enabled
- Use the servlet container/reverse proxy's normal authentication and authorization mechanisms where required
Remote JDBC is a JDBC transport layer. It should be deployed as part of a properly secured application/server architecture.
<dependency>
<groupId>com.sibvisions.rjdbc</groupId>
<artifactId>rjdbc-driver</artifactId>
<version>1.14</version>
</dependency>
<dependency>
<groupId>com.sibvisions.rjdbc</groupId>
<artifactId>rjdbc-server-javax</artifactId>
<version>1.14</version>
</dependency>
<dependency>
<groupId>com.sibvisions.rjdbc</groupId>
<artifactId>rjdbc-server-jakarta</artifactId>
<version>1.14</version>
</dependency>
Remote JDBC is licensed under the GNU General Public License, version 3.0 (GPL-3.0).
See LICENSE.
