Java API (gRPC)
ArcadeDB provides a high-performance gRPC-based Java library for remote database communication. gRPC (gRPC Remote Procedure Call) is a modern, open-source, high-performance RPC framework that can efficiently connect services in and across data centers.
Why Use gRPC for ArcadeDB?
gRPC offers several advantages over traditional HTTP-based communication:
-
High Performance: gRPC uses HTTP/2 for transport, providing lower latency and higher throughput compared to traditional HTTP/1.1
-
Efficient Binary Protocol: Uses Protocol Buffers for serialization, resulting in smaller message sizes and faster parsing
-
Streaming Support: Built-in support for bidirectional streaming, ideal for real-time applications
-
Language Agnostic: While this guide focuses on Java, gRPC supports multiple programming languages with consistent APIs
-
Low Latency: Optimized for scenarios requiring minimal latency and maximum throughput
-
Connection Multiplexing: Multiple requests can be sent over a single TCP connection
gRPC is particularly well-suited for:
-
Real-time applications requiring fast data access
-
Microservices architectures
-
High-throughput data processing
-
Mobile applications with limited bandwidth
-
Services requiring bidirectional streaming
RemoteGrpcServer Class
The RemoteGrpcServer class manages connections to the gRPC server and provides server-level operations such as creating databases, listing available databases, and managing server resources.
Key features:
-
Establishes and maintains the connection to the ArcadeDB gRPC server
-
Handles authentication and security
-
Provides methods for database lifecycle management
-
Supports connection pooling and resource management
RemoteGrpcDatabase Class
The RemoteGrpcDatabase class is used to work with a specific remote database instance via gRPC. It provides methods for executing queries, commands, and transactions with optimal performance characteristics.
Key features:
-
Execute SQL queries and commands
-
Support for parameterized queries (both named and positional)
-
Transaction management (begin, commit, rollback)
-
Schema manipulation
-
Data manipulation (insert, update, delete)
-
High-performance data retrieval
Maven Dependencies
Add the following dependency in your Maven pom.xml file under the tag <dependencies>:
<dependency>
<groupId>com.arcadedb</groupId>
<artifactId>arcadedb-grpc-client</artifactId>
<version>26.5.1</version>
</dependency>
| The gRPC client dependency includes all necessary Protocol Buffer definitions and gRPC runtime libraries. No additional dependencies are required. |
10-Minute Tutorial
This tutorial will guide you through the essential operations using ArcadeDB’s gRPC API, from establishing a connection to executing various types of database operations.
Connect to a gRPC Server
To begin working with ArcadeDB via gRPC, you need to establish a connection to the server. The gRPC API provides two main classes:
-
RemoteGrpcServer, to manage server connections and create databases -
RemoteGrpcDatabase, to work with a specific remote database instance
The gRPC server listens on port 50051 by default (different from the HTTP port 2480).
Create a RemoteGrpcServer Instance
First, create a RemoteGrpcServer instance to connect to your ArcadeDB server:
RemoteGrpcServer server = new RemoteGrpcServer(
"localhost", // Server hostname
50051, // gRPC port (default: 50051)
"root", // Username
"password", // Password
false, // Use TLS/SSL (false for development)
List.of() // Additional channel credentials (if needed)
);
The constructor parameters are:
-
hostname: The server hostname or IP address -
port: The gRPC port (typically 50051) -
username: Database user credentials -
password: User password -
useTls: Whether to use TLS/SSL encryption -
channelCredentials: Optional additional credentials for advanced security configurations
Before creating or accessing a database, you can check if it exists:
if (!server.exists("mydb")) {
server.create("mydb");
System.out.println("Database 'mydb' created successfully");
}
You can also list all available databases on the server:
List<String> databases = server.databases();
System.out.println("Available databases: " + databases);
Create a RemoteGrpcDatabase Instance
Once the server connection is established and the database exists, create a RemoteGrpcDatabase instance to interact with a specific database:
RemoteGrpcDatabase database = new RemoteGrpcDatabase(
server, // RemoteGrpcServer instance
"localhost", // Server hostname
50051, // gRPC port
2480, // HTTP port (for fallback operations)
"mydb", // Database name
"root", // Username
"password" // Password
);
Like RemoteDatabase, the RemoteGrpcDatabase class is not thread-safe. Each thread should create its own instance. Avoid sharing RemoteGrpcDatabase instances across threads to prevent unexpected behavior.
|
Best practice for thread safety:
// Create database instance in method scope, not as a field
public void performDatabaseOperation() {
try (RemoteGrpcDatabase database = new RemoteGrpcDatabase(
server, "localhost", 50051, 2480, "mydb", "root", "password"
)) {
// Perform operations
ResultSet results = database.query("sql", "SELECT * FROM MyType");
// Process results...
}
}
Create Schema with SQL Commands
With the database connection established, you can create your schema. The gRPC API supports both single SQL statements and SQL scripts:
// Using sqlscript for multiple statements in one transaction
String schema = """
CREATE VERTEX TYPE Article IF NOT EXISTS;
CREATE PROPERTY Article.id IF NOT EXISTS INTEGER;
CREATE PROPERTY Article.title IF NOT EXISTS STRING;
CREATE PROPERTY Article.content IF NOT EXISTS STRING;
CREATE PROPERTY Article.published IF NOT EXISTS DATETIME;
CREATE PROPERTY Article.author IF NOT EXISTS STRING;
CREATE INDEX IF NOT EXISTS ON Article(id) UNIQUE;
""";
database.command("sqlscript", schema);
System.out.println("Schema created successfully");
The sqlscript language is recommended for schema creation because:
-
All statements execute within a single transaction
-
Improved performance due to reduced network round-trips
-
Atomic operations - either all succeed or all fail
Alternatively, you can execute statements individually:
database.begin();
try {
database.command("sql", "CREATE VERTEX TYPE Article IF NOT EXISTS");
database.command("sql", "CREATE PROPERTY Article.id IF NOT EXISTS INTEGER");
database.command("sql", "CREATE PROPERTY Article.title IF NOT EXISTS STRING");
database.command("sql", "CREATE INDEX IF NOT EXISTS ON Article(id) UNIQUE");
database.commit();
System.out.println("Schema created successfully");
} catch (Exception e) {
database.rollback();
System.err.println("Schema creation failed: " + e.getMessage());
}
Execute Queries
The gRPC API provides optimized query execution with support for both simple and parameterized queries:
// Simple query
ResultSet resultSet = database.query("sql", "SELECT * FROM Article");
// Process results
while (resultSet.hasNext()) {
Result result = resultSet.next();
System.out.println("Article: " + result.toMap());
}
Using parameterized queries (recommended for security and performance):
// Named parameters
ResultSet resultSet = database.query(
"sql",
"SELECT * FROM Article WHERE author = :author AND published > :date",
Map.of(
"author", "John Doe",
"date", LocalDateTime.now().minusDays(30)
)
);
// Positional parameters
ResultSet resultSet2 = database.query(
"sql",
"SELECT * FROM Article WHERE id = ? AND published = ?",
1,
LocalDateTime.now()
);
Working with query results:
// Convert results to a list of maps
List<Map<String, Object>> articles = database.query("sql", "SELECT * FROM Article")
.stream()
.map(Result::toMap)
.collect(Collectors.toList());
// Find first result
Optional<Map<String, Object>> firstArticle = database.query(
"sql",
"SELECT * FROM Article WHERE id = :id",
Map.of("id", 1)
)
.stream()
.findFirst()
.map(Result::toMap);
if (firstArticle.isPresent()) {
System.out.println("Found article: " + firstArticle.get());
}
Update Data
Updating existing records is straightforward with the gRPC API:
// Simple update with positional parameters
database.command(
"sql",
"UPDATE Article SET title = ? WHERE id = ?",
"Updated Article Title",
3
);
// Update with named parameters
database.command(
"sql",
"UPDATE Article SET title = :title, content = :content WHERE id = :id",
Map.of(
"title", "Understanding gRPC in ArcadeDB",
"content", "gRPC provides high-performance communication...",
"id", 3
)
);
// Update with complex expressions
database.command(
"sql",
"UPDATE Article SET published = :now, views = views + 1 WHERE id = :id",
Map.of(
"now", LocalDateTime.now(),
"id", 3
)
);
Batch updates using transactions:
database.transaction(() -> {
List<Integer> articleIds = List.of(1, 2, 3, 4, 5);
for (Integer id : articleIds) {
database.command(
"sql",
"UPDATE Article SET views = views + 1 WHERE id = ?",
id
);
}
System.out.println("Updated " + articleIds.size() + " articles");
});
Insert Data
The gRPC API supports multiple approaches for inserting data:
// Traditional INSERT with values
database.command(
"sql",
"INSERT INTO Article (id, title, author, published) VALUES (?, ?, ?, ?)",
1,
"Getting Started with ArcadeDB",
"Jane Smith",
LocalDateTime.now()
);
// INSERT with named parameters
database.command(
"sql",
"INSERT INTO Article (id, title, author, published) VALUES (:id, :title, :author, :published)",
Map.of(
"id", 2,
"title", "Advanced Query Techniques",
"author", "John Doe",
"published", LocalDateTime.now()
)
);
Using JSON content for complex documents:
// INSERT with JSON CONTENT
String jsonContent = """
{
"id": 3,
"title": "gRPC Performance Guide",
"content": "Learn how to optimize your gRPC implementations...",
"author": "Alice Johnson",
"published": "2024-03-15T10:30:00",
"tags": ["performance", "gRPC", "optimization"],
"metadata": {
"category": "Tutorial",
"difficulty": "Intermediate"
}
}
""";
database.command("sql", "INSERT INTO Article CONTENT " + jsonContent);
Bulk insert operations:
database.transaction(() -> {
List<Map<String, Object>> articles = List.of(
Map.of("id", 10, "title", "Article 10", "author", "Author A"),
Map.of("id", 11, "title", "Article 11", "author", "Author B"),
Map.of("id", 12, "title", "Article 12", "author", "Author C")
);
for (Map<String, Object> article : articles) {
database.command(
"sql",
"INSERT INTO Article (id, title, author) VALUES (:id, :title, :author)",
article
);
}
System.out.println("Inserted " + articles.size() + " articles");
});
Create Vertices with RETURN Clause
When creating vertices, you often need to retrieve the created record’s RID (Record ID) or other properties. The RETURN clause makes this efficient:
// Create vertex and return the new record
ResultSet result = database.command(
"sql",
"CREATE VERTEX Article SET id = ?, title = ?, author = ? RETURN @this",
100,
"Real-time Data Processing",
"Bob Wilson"
);
// Get the created vertex
if (result.hasNext()) {
Result vertex = result.next();
String rid = vertex.getIdentity().toString();
System.out.println("Created vertex with RID: " + rid);
System.out.println("Vertex data: " + vertex.toMap());
}
Return specific properties:
// Return only the RID
ResultSet result = database.command(
"sql",
"CREATE VERTEX Article SET id = :id, title = :title RETURN @rid",
Map.of(
"id", 101,
"title", "Graph Traversal Patterns"
)
);
if (result.hasNext()) {
Result vertex = result.next();
System.out.println("New vertex RID: " + vertex.getProperty("@rid"));
}
// Return multiple properties
ResultSet result2 = database.command(
"sql",
"CREATE VERTEX Article SET id = :id, title = :title, published = :now " +
"RETURN @rid, id, title",
Map.of(
"id", 102,
"title", "Distributed Database Architecture",
"now", LocalDateTime.now()
)
);
Creating edges between vertices:
// Create vertices
ResultSet author = database.command(
"sql",
"CREATE VERTEX Author SET name = ? RETURN @rid",
"Emily Davis"
);
if (author.hasNext()) {
String authorRid = author.next().getProperty("@rid").toString();
ResultSet article = database.command(
"sql",
"CREATE VERTEX Article SET title = ? RETURN @rid",
"Mastering Graph Databases"
);
if (article.hasNext()) {
String articleRid = article.next().getProperty("@rid").toString();
// Create edge connecting them
database.command(
"sql",
"CREATE EDGE Authored FROM ? TO ?",
authorRid,
articleRid
);
System.out.println("Created relationship between author and article");
} else {
System.err.println("Failed to create article, no RID returned.");
}
} else {
System.err.println("Failed to create author, no RID returned.");
}
Transaction Management
The gRPC API provides comprehensive transaction support for ensuring data consistency:
// Explicit transaction control
database.begin();
try {
database.command("sql", "CREATE VERTEX Article SET id = 200");
database.command("sql", "CREATE VERTEX Article SET id = 201");
database.commit();
System.out.println("Transaction committed successfully");
} catch (Exception e) {
database.rollback();
System.err.println("Transaction rolled back due to error: " + e.getMessage());
}
// Using transaction lambda (recommended)
database.transaction(() -> {
database.command("sql", "CREATE VERTEX Article SET id = 300");
database.command("sql", "CREATE VERTEX Article SET id = 301");
// Automatically commits if no exception, rolls back on exception
});
Error Handling
Proper error handling is essential for robust applications:
try {
RemoteGrpcDatabase database = new RemoteGrpcDatabase(
server, "localhost", 50051, 2480, "mydb", "root", "password"
);
ResultSet results = database.query("sql", "SELECT * FROM Article");
// Process results...
} catch (SecurityException e) {
System.err.println("Authentication failed: " + e.getMessage());
} catch (DatabaseOperationException e) {
System.err.println("Database operation failed: " + e.getMessage());
} catch (Exception e) {
System.err.println("Unexpected error: " + e.getMessage());
e.printStackTrace();
}
Performance Tips
To get the best performance from the gRPC API:
-
Use Connection Pooling: Create a single
RemoteGrpcServerinstance and reuse it across your application -
Batch Operations: Group multiple operations in transactions to reduce network round-trips
-
Parameterized Queries: Always use parameterized queries for better performance and security
-
Use sqlscript: For multiple statements, use
sqlscriptto execute them in a single transaction -
Close Resources: Ensure proper cleanup of database instances, especially in multi-threaded environments
-
Stream Results: For large result sets, process results as you iterate rather than loading everything into memory
-
Enable TLS in Production: Use TLS/SSL in production for security without significant performance impact
Complete Example
Here’s a complete example demonstrating the gRPC API usage:
import com.arcadedb.remote.grpc.RemoteGrpcServer;
import com.arcadedb.remote.grpc.RemoteGrpcDatabase;
import com.arcadedb.query.sql.executor.Result;
import com.arcadedb.query.sql.executor.ResultSet;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
public class ArcadeDBGrpcExample {
public static void main(String[] args) {
// Connect to gRPC server
try (RemoteGrpcServer server = new RemoteGrpcServer(
"localhost", 50051, "root", "password", false, List.of()
)) {
// Create database if it doesn't exist
if (!server.exists("mydb")) {
server.create("mydb");
}
// Create database instance
try (RemoteGrpcDatabase database = new RemoteGrpcDatabase(
server, "localhost", 50051, 2480, "mydb", "root", "password"
)) {
// Create schema
String schema = """
CREATE VERTEX TYPE Article IF NOT EXISTS;
CREATE PROPERTY Article.id IF NOT EXISTS INTEGER;
CREATE PROPERTY Article.title IF NOT EXISTS STRING;
CREATE PROPERTY Article.author IF NOT EXISTS STRING;
CREATE INDEX IF NOT EXISTS ON Article(id) UNIQUE;
""";
database.command("sqlscript", schema);
// Insert data
database.transaction(() -> {
database.command(
"sql",
"INSERT INTO Article (id, title, author, published) VALUES (:id, :title, :author, :published)",
Map.of(
"id", 1,
"title", "Introduction to gRPC",
"author", "Jane Doe",
"published", LocalDateTime.now()
)
);
});
// Query data
ResultSet results = database.query(
"sql",
"SELECT * FROM Article WHERE author = :author",
Map.of("author", "Jane Doe")
);
// Process results
results.stream()
.map(Result::toMap)
.forEach(article ->
System.out.println("Article: " + article.get("title"))
);
System.out.println("gRPC API example completed successfully");
}
}
}
}
See Also
-
Java API (Remote) - HTTP-based remote API
-
Java API (Local) - Embedded database API
-
Java API Reference - Complete API documentation