Skip to content

Java SDK

The ParticleDB Java SDK is a JDBC 4.2 driver built natively against the PDB wire protocol. It is pure Java + Netty — no JNI, no pgjdbc dependency. The driver multiplexes (HTTP/2-style) over one TCP connection, with N concurrent streams per connection. Falls back to single-stream when talking to v1 servers.

Coordinates: ai.particledb:particledb-jdbc:1.0.0

For an in-depth JDBC reference and the full URL / TLS / pool option matrix, see the dedicated JDBC Driver page. This page is the quickstart.

  • Java 17+ (Java 11 is supported for compile + DDL/DML; Arrow result-row decoding needs JDK 17 + the --add-opens flags listed below)
  • Maven 3.9+ or Gradle 8+
  • A running ParticleDB server (PDB wire on port 5440; the JDBC driver speaks PDB native wire, not PostgreSQL wire)

Now on Maven Central — resolves from any default Maven or Gradle build with no extra repository declaration.

<dependencies>
<dependency>
<groupId>ai.particledb</groupId>
<artifactId>particledb-jdbc</artifactId>
<version>1.0.0</version>
</dependency>
<!-- Required for SELECT result-row decoding (Arrow IPC). -->
<dependency>
<groupId>org.apache.arrow</groupId>
<artifactId>arrow-vector</artifactId>
<version>15.0.2</version>
</dependency>
<dependency>
<groupId>org.apache.arrow</groupId>
<artifactId>arrow-memory-netty</artifactId>
<version>15.0.2</version>
</dependency>
</dependencies>

Apache Arrow Java needs reflective access to ByteBuffer internals. Add to your JVM startup arguments:

--add-opens=java.base/java.nio=ALL-UNNAMED
--add-opens=java.base/sun.nio.ch=ALL-UNNAMED

Without these the driver will throw a clear, actionable error on the first SELECT result-set decode (it intentionally does NOT silently fall back to raw bytes).

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
public class Hello {
public static void main(String[] args) throws Exception {
Class.forName("org.particledb.Driver");
try (Connection c = DriverManager.getConnection(
"jdbc:particledb://127.0.0.1:5440/default");
Statement s = c.createStatement();
ResultSet rs = s.executeQuery("SELECT 1")) {
while (rs.next()) {
System.out.println(rs.getInt(1));
}
}
}
}
try (Connection c = DriverManager.getConnection(
"jdbc:particledb://127.0.0.1:5440/default")) {
try (Statement s = c.createStatement()) {
s.execute("CREATE TABLE users (id INT PRIMARY KEY, name TEXT, score DOUBLE)");
}
try (PreparedStatement ins = c.prepareStatement(
"INSERT INTO users (id, name, score) VALUES (?,?,?)")) {
ins.setInt(1, 1); ins.setString(2, "alice"); ins.setDouble(3, 92.5);
ins.executeUpdate();
}
try (PreparedStatement sel = c.prepareStatement(
"SELECT name, score FROM users WHERE id = ?")) {
sel.setInt(1, 1);
try (ResultSet rs = sel.executeQuery()) {
while (rs.next()) {
System.out.printf("name=%s score=%.2f%n",
rs.getString("name"), rs.getDouble("score"));
}
}
}
}

The driver ships no built-in pool. Wrap it in HikariCP for fan-out:

HikariConfig cfg = new HikariConfig();
cfg.setJdbcUrl("jdbc:particledb://127.0.0.1:5440/default");
cfg.setMaximumPoolSize(10);
cfg.setMinimumIdle(1);
cfg.setConnectionTimeout(30_000);
try (HikariDataSource ds = new HikariDataSource(cfg)) {
try (Connection c = ds.getConnection()) { /* ... */ }
}

Note: the PDB wire transport itself already multiplexes streams per TCP connection, so a small pool (≤10) is usually sufficient.

Properties p = new Properties();
p.setProperty("user", "app");
p.setProperty("password", System.getenv("PDB_PASSWORD"));
p.setProperty("sslMode", "verify-full"); // disable | require | verify-ca | verify-full
p.setProperty("sslRootCert", "/etc/ssl/internal-ca.crt");
// p.setProperty("sslCert", "/run/secrets/pdb-client.crt"); // mTLS
// p.setProperty("sslKey", "/run/secrets/pdb-client.key");
try (Connection c = DriverManager.getConnection(
"jdbc:particledb://db.example.com:5443/postgres", p)) {
// ...
}

Modes match pgjdbc + the canonical Connection Options spec.

jdbc:particledb://host:port/database?<options>
OptionDefaultDescription
prepareThreshold5Executions before server-side prepare.
preparedStatementCacheQueries256Client-side prepared cache size (entries).
preparedStatementCacheSizeMiB5Client-side prepared cache cap (MiB).
maxStreamsPerConn64Wire-v2 multiplex stream cap per TCP.
sslModedisableTLS mode (disable / require / verify-ca / verify-full).
preferUnixSockettrueTry /tmp/.s.PDB.<port> first when local.
connectTimeout30000TCP + handshake timeout (ms).

ParticleDB also exposes the PostgreSQL wire on port 5432. If you have an existing pgjdbc-based stack and don’t want to migrate to the native driver, you can keep using stock pgjdbc:

<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.7.4</version>
</dependency>
Connection c = DriverManager.getConnection(
"jdbc:postgresql://127.0.0.1:5432/mydb", "particledb", "");

PG-wire supports the full pgjdbc feature set including server-side prepared statements (via prepareThreshold), pipelined execution, and interactive transactions with rollback-after-write semantics — useful if your app relies on Connection.rollback() after a partial write.

  • The PDB native wire treats BEGIN/COMMIT/ROLLBACK as batch markers, not full ACID brackets — Connection.rollback() after flushed writes will NOT undo them on PDB native wire. For interactive rollback, connect via PG wire (port 5432) using stock pgjdbc.
  • DataSource bean setters land on the native driver; JNDI registration for app-server deployments is on the v1.1 roadmap.
  • CallableStatement for stored procedures is on the v1.1 roadmap.