ARCHIVED: this code has moved over to https://github.com/rqlite/rqlite-jdbc
l4zr is a minimal (~130KB, zero dependencies), Type 4 JDBC driver for rqlite,
a lightweight, distributed relational database built on top of SQLite.
This driver enables Java applications to interact with rqlite over HTTP, supporting standard
JDBC operations like queries, updates, and batch processing in a clustered environment.
- JDBC Compliance: Supports core JDBC APIs, including
Connection,Statement,PreparedStatement, andResultSet. - Atomic Transactions: Executes multiple statements atomically using rqlite’s
transaction=truemode via batch operations. - Clustered Environment Support: Configurable options for read consistency, write queuing, and timeouts to handle rqlite’s distributed nature.
- Schema and Metadata Access: Query table metadata, primary keys, foreign keys, and indexes (see L4DriverTest).
- Java 11 or higher
rqliteserver running (e.g.,http://localhost:4001)
Install from Maven Central
io.vacco.l4zr:l4zr:[version]
The driver version corresponds to the last known rqlite release the driver was tested against.
Connect to an rqlite instance and execute queries using standard JDBC APIs.
import java.sql.*;
var url = "jdbc:sqlite:http://localhost:4001";
try (Connection conn = DriverManager.getConnection(url)) {
var stmt = conn.createStatement();
stmt.execute("CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT, age INTEGER)");
var ps = conn.prepareStatement("INSERT INTO users (name, age) VALUES (?, ?)");
ps.setString(1, "Alice");
ps.setInt(2, 30);
ps.executeUpdate();
var rs = stmt.executeQuery("SELECT * FROM users");
while (rs.next()) {
System.out.println("ID: " + rs.getInt("id") + ", Name: " + rs.getString("name") + ", Age: " + rs.getInt("age"));
}
}
rqlite executes statements atomically with transaction=true. Use batch operations for multi-statement transactions.
Using Statement:
Statement stmt = conn.createStatement();
stmt.addBatch("INSERT INTO users (name, age) VALUES ('Fiona', 25)");
stmt.addBatch("INSERT INTO users (name, age) VALUES ('Sinead', 28)");
int[] updateCounts = stmt.executeBatch(); // Executes atomically
Using PreparedStatement:
PreparedStatement ps = conn.prepareStatement("INSERT INTO users (name, age) VALUES (?, ?)");
ps.setString(1, "Fiona");
ps.setInt(2, 25);
ps.addBatch();
ps.setString(1, "Sinead");
ps.setInt(2, 28);
ps.addBatch();
int[] updateCounts = ps.executeBatch(); // Executes atomically
See L4PsTest for advanced examples with various data types, streams, and LOBs.
Customize the driver’s behavior via JDBC URL parameters, see L4Options. Below are the available options, their defaults, and their purposes.
These options come from rqlite's Developer Guide
| Property Key | Type | Default Value | Description |
|---|---|---|---|
baseUrl |
String |
null |
The base URL of the RQLite server (e.g., http://localhost:4001). |
user |
String |
null |
Username for RQLite server authentication. |
password |
String |
null |
Password for RQLite server authentication. |
cacert |
String |
null |
Path to the CA certificate for SSL/TLS connections. |
insecure |
boolean |
false |
If true, disables SSL/TLS verification (not recommended for production). |
timeoutSec |
long |
5 |
Timeout for HTTP requests in seconds. |
queue |
boolean |
false |
If true, enables queuing of requests on the RQLite server. |
wait |
boolean |
true |
If true, waits for the request to be processed by the RQLite leader. |
level |
L4Level |
L4Level.linearizable |
Consistency level for queries (none, weak, strong, linearizable). |
linearizableTimeoutSec |
long |
5 |
Timeout for linearizable consistency queries in seconds. |
freshnessSec |
long |
5 |
Maximum age of data for freshness-based queries in seconds. |
freshnessStrict |
boolean |
false |
If true, enforces strict freshness for queries. |
Example JDBC URL:
String url = "jdbc:sqlite:http://localhost:4001?timeoutSec=5&level=strong&freshnessSec=1";Result sets are held in memory (mapped from rqlite’s JSON responses to JDBC ResultSet). Write queries that return small datasets to avoid memory issues.
Only the main SQLite database is reported as a catalog to JDBC.
The driver does nothing when calling commit, or rollback on Connection instances due to rqlite's Transaction support.
Call setAutoCommit(true) on a connection, and call executeBatch on Statement instances for atomic multi-statement execution, which effectively appends transaction=true to the underlying rqlite HTTP request.
Only TRANSACTION_SERIALIZABLE is supported, with linearizable read consistency by default. Setting level=weak or level=none may introduce read inconsistencies.
User-defined SQL types (UDTs) are not supported. getTypeMap and setTypeMap are implemented for compliance but have no effect.
Contributions are welcome! Please submit issues or pull requests to this GitHub repository.
Requires Gradle 8.1 or later.
Create a file with the following content at ~/.gsOrgConfig.json:
{
"orgId": "vacco-oss",
"orgConfigUrl": "http://56db25d3f6c39937b48e-6eaf716421c53330be45fa9d36560381.r85.cf2.rackcdn.com/org-config/vacco.json"
}
Then run:
gradle clean build