LindormTSDB SDK provides three categories of interfaces: management interfaces for DDL (Data Definition Language) and DCL (Data Control Language) operations, write interfaces for ingesting time-series records, and a query interface for retrieving data with SQL.
Management interfaces
Management interfaces execute SQL statements against LindormTSDB. Two overloaded methods are available:
| Method signature | Description |
|---|---|
Result execute(String sql) | Executes a SQL statement against the default database |
Result execute(String database, String sql) | Executes a SQL statement against the specified database |
The Result object contains the execution output:
| Field | Type | Description |
|---|---|---|
columns | List<String> | Column names in the returned results |
metadata | List<String> | Data types of the columns |
rows | List<List<Object>> | Results returned row by row |
Manage databases and tables
Use DDL statements to create, describe, and drop databases or tables. The following example walks through a complete create-and-drop lifecycle:
// 1. List existing databases.
String showDatabase = "show databases";
Result result = lindormTSDBClient.execute(showDatabase);
System.out.println("before create, db list: " +
result.getRows().stream().map(e -> (String) e.get(0)).collect(Collectors.toList()));
// 2. Create a database named "demo".
String createDatabase = "create database demo";
result = lindormTSDBClient.execute(createDatabase);
System.out.println("create database:" + result.isSuccessful());
// 3. Verify the database was created.
result = lindormTSDBClient.execute(showDatabase);
System.out.println("after create, db list: " +
result.getRows().stream().map(e -> (String) e.get(0)).collect(Collectors.toList()));
String database = "demo";
// 4. List existing tables in the database.
String showTables = "show tables";
result = lindormTSDBClient.execute(database, showTables);
System.out.println("before create, table list: " +
result.getRows().stream().map(e -> (String) e.get(0)).collect(Collectors.toList()));
// 5. Create a table.
String createTable = "CREATE TABLE sensor (device_id VARCHAR TAG, region VARCHAR TAG, " +
"time BIGINT, temperature DOUBLE, humidity DOUBLE, PRIMARY KEY(device_id))";
result = lindormTSDBClient.execute(database, createTable);
System.out.println("create table: " + result.isSuccessful());
// 6. Verify the table was created.
result = lindormTSDBClient.execute(database, showTables);
System.out.println("after create, table list: " +
result.getRows().stream().map(e -> (String) e.get(0)).collect(Collectors.toList()));
// 7. Describe the table schema.
String describeTable = "describe table sensor";
result = lindormTSDBClient.execute(database, describeTable);
System.out.println("------------ describe table -------------------");
List<String> columns = result.getColumns();
System.out.println("columns: " + columns);
List<String> metadata = result.getMetadata();
System.out.println("metadata: " + metadata);
List<List<Object>> rows = result.getRows();
for (int i = 0, size = rows.size(); i < size; i++) {
List<Object> row = rows.get(i);
System.out.println("column #" + i + " : " + row);
}
System.out.println("------------ describe table -------------------");
// 8. Drop the table.
String dropTable = "drop table sensor";
result = lindormTSDBClient.execute(database, dropTable);
System.out.println("drop table: " + result.isSuccessful());
// 9. Verify the table was dropped.
result = lindormTSDBClient.execute(database, showTables);
System.out.println("after drop, table list: " +
result.getRows().stream().map(e -> (String) e.get(0)).collect(Collectors.toList()));
// 10. Drop the database.
String dropDatabase = "drop database demo";
result = lindormTSDBClient.execute(dropDatabase);
System.out.println("drop database:" + result.isSuccessful());
// 11. Verify the database was dropped.
result = lindormTSDBClient.execute(showDatabase);
System.out.println("after drop, db list : " +
result.getRows().stream().map(e -> (String) e.get(0)).collect(Collectors.toList()));Expected output:
before create, db list: [default]
create database:true
after create, db list: [default, demo]
before create, table list: []
create table: true
after create, table list: [sensor]
------------ describe table -------------------
columns: [columnName, typeName, columnKind]
metadata: [VARCHAR, VARCHAR, VARCHAR]
column #0 : [device_id, VARCHAR, TAG]
column #1 : [region, VARCHAR, TAG]
column #2 : [time, TIMESTAMP, TIMESTAMP]
column #3 : [temperature, DOUBLE, FIELD]
column #4 : [humidity, DOUBLE, FIELD]
------------ describe table -------------------
drop table: true
after drop, table list: []
drop database:true
after drop, db list : [default]DDL operations for continuous queries are not covered here. For the full SQL syntax supported by LindormTSDB, see SQL syntax.
Write interfaces
LindormTSDB SDK writes data asynchronously by default to maximize throughput. The write interfaces support:
Single-record and batch writes (batch writes reduce lock contention in the async queue and are recommended)
Two result-handling patterns:
CompletableFuture<WriteResult>for inline processing, andCallbackfor event-driven handlingSynchronous writes by calling
.join()on the returnedCompletableFuture
Build a write record
A Record object holds a single row to write. Specify the table name, timestamp, tags, and field values:
Record record = Record
.table("sensor") // Table name
.time(currentTime) // Timestamp in milliseconds
.tag("device_id", "F07A1260") // Tag: indexed key-value dimension
.tag("region", "north-cn")
.addField("temperature", 12.1) // Field: non-indexed metric value
.addField("humidity", 45.0)
.build();By default, the SDK validates character validity when building a Record. Pass false to build() to skip validation.
Write with CompletableFuture
All overloads return CompletableFuture<WriteResult>. Use batch writes to reduce lock contention in the asynchronous queue.
| Method signature | Description |
|---|---|
CompletableFuture<WriteResult> write(Record record) | Writes a single record to the default database |
CompletableFuture<WriteResult> write(String database, Record record) | Writes a single record to the specified database |
CompletableFuture<WriteResult> write(List<Record> records) | Writes a batch of records to the default database (recommended) |
CompletableFuture<WriteResult> write(String database, List<Record> records) | Writes a batch of records to the specified database (recommended) |
Single record:
// Default database
CompletableFuture<WriteResult> future = lindormTSDBClient.write(record);
// Specified database
String database = "demo";
CompletableFuture<WriteResult> future = lindormTSDBClient.write(database, record);Batch write (recommended):
List<Record> records;
// Default database
CompletableFuture<WriteResult> future = lindormTSDBClient.write(records);
// Specified database
String database = "demo";
CompletableFuture<WriteResult> future = lindormTSDBClient.write(database, records);Handle the result:
CompletableFuture<WriteResult> future = lindormTSDBClient.write(records);
future.whenComplete((r, ex) -> {
if (ex != null) {
// Write submission failed.
System.out.println("Failed to write.");
Throwable throwable = ExceptionUtils.getRootCause(ex);
if (throwable instanceof LindormTSDBException) {
LindormTSDBException e = (LindormTSDBException) throwable;
System.out.println("Error code: " + e.getCode());
System.out.println("SQL state: " + e.getSqlstate());
System.out.println("Error message: " + e.getMessage());
} else {
throwable.printStackTrace();
}
} else {
// Write completed.
if (r.isSuccessful()) {
System.out.println("Write successfully.");
} else {
System.out.println("Write failure.");
}
}
});Do not perform complex or time-consuming calculations inside whenComplete. Offload such work to an independent thread pool. For error code details, see Common error codes.
Write with a callback
Pass a Callback to the write() method. onCompletion receives the write result, the corresponding records, and any exception.
public interface Callback {
void onCompletion(WriteResult result, List<Record> records, Throwable e);
}| Method signature | Description |
|---|---|
write(Record record, Callback callback) | Writes a single record to the default database with a callback |
write(String database, Record record, Callback callback) | Writes a single record to the specified database with a callback |
write(List<Record> records, Callback callback) | Writes a batch of records to the default database with a callback (recommended) |
write(String database, List<Record> records, Callback callback) | Writes a batch of records to the specified database with a callback (recommended) |
Implement and pass the callback:
Callback callback = new Callback() {
@Override
public void onCompletion(WriteResult result, List<Record> list, Throwable throwable) {
if (throwable != null) {
// Write failed.
if (throwable instanceof LindormTSDBException) {
LindormTSDBException ex = (LindormTSDBException) throwable;
System.out.println("errorCode: " + ex.getCode());
System.out.println("sqlstate: " + ex.getSqlstate());
System.out.println("message: " + ex.getMessage());
} else {
throwable.printStackTrace();
}
} else {
if (result.isSuccessful()) {
System.out.println("Write successfully.");
} else {
System.out.println("Write failure.");
}
}
}
};
// Batch write — recommended
List<Record> records;
lindormTSDBClient.write(records, callback);
// Single record
lindormTSDBClient.write(record, callback);Do not perform complex or time-consuming calculations inside onCompletion. Offload such work to an independent thread pool. For error code details, see Common error codes.
Query interface
The query interface executes SQL statements and streams results back in chunks. All overloads return a ResultSet.
| Method signature | Description |
|---|---|
ResultSet query(String sql) | Queries the default database; returns up to 1,000 rows per chunk |
ResultSet query(String database, String sql) | Queries the specified database; returns up to 1,000 rows per chunk |
ResultSet query(String database, String sql, int chunkSize) | Queries the specified database with a custom chunk size |
Parameters:
| Parameter | Type | Description |
|---|---|---|
database | String | Name of the database to query |
sql | String | SQL statement to execute. For supported syntax, see SQL syntax. |
chunkSize | int | Number of rows returned per batch. Default: 1,000. |
Process query results
Iterate ResultSet with next() until it returns null, then close the result set to release I/O resources:
public interface ResultSet extends Closeable {
QueryResult next();
void close();
}Each QueryResult object contains:
| Field | Type | Description |
|---|---|---|
columns | List<String> | Column names in the query results |
metadata | List<String> | Data types of the columns. See Data types. |
rows | List<List<Object>> | Query results returned row by row |
Example:
String sql = "select * from sensor";
int chunkSize = 100;
ResultSet resultSet = lindormTSDBClient.query("demo", sql, chunkSize);
try {
QueryResult result = null;
// Iterate until next() returns null — all results have been retrieved.
while ((result = resultSet.next()) != null) {
List<String> columns = result.getColumns();
System.out.println("columns: " + columns);
List<String> metadata = result.getMetadata();
System.out.println("metadata: " + metadata);
List<List<Object>> rows = result.getRows();
for (int i = 0, size = rows.size(); i < size; i++) {
List<Object> row = rows.get(i);
System.out.println("row #" + i + " : " + row);
}
}
} finally {
// Always close ResultSet after the query — whether it succeeds or fails.
resultSet.close();
}Always call resultSet.close() after the query completes, regardless of success or failure. Failing to do so causes a connection leak.