JDBC Type 4 driver for MySQL with X DevAPI support for document store operations
Fluent statement builders for Create, Read, Update, and Delete operations on collections and tables. These interfaces provide a chainable API for building complex queries and modifications.
The base interface for all X DevAPI statements, providing common functionality for execution and parameter binding.
package com.mysql.cj.xdevapi;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
public interface Statement<STMT_T, RES_T> {
// Lock contention options
enum LockContention {
DEFAULT, // Wait until the row lock is released
NOWAIT, // Do not wait to acquire row lock; fail with error if locked
SKIP_LOCKED; // Do not wait; remove locked rows from result set
}
// Synchronous execution
RES_T execute();
// Asynchronous execution
CompletableFuture<RES_T> executeAsync();
// Parameter binding
// Note: Some bind methods have default implementations that throw UnsupportedOperationException
// for statements that don't support parameter binding. Check specific statement implementations.
STMT_T clearBindings();
STMT_T bind(String argName, Object value);
STMT_T bind(Map<String, Object> values);
STMT_T bind(List<Object> values);
STMT_T bind(Object... values);
}Usage:
// Asynchronous execution
CompletableFuture<DocResult> futureResult = collection.find("age > :minAge")
.bind("minAge", 18)
.executeAsync();
futureResult.thenAccept(result -> {
while (result.hasNext()) {
DbDoc doc = result.next();
System.out.println(doc.toString());
}
});
// Multiple parameter binding approaches
FindStatement stmt = collection.find("name = :name AND age = :age");
// Bind individually
stmt.bind("name", "Alice").bind("age", 30);
// Bind with map
Map<String, Object> params = new HashMap<>();
params.put("name", "Alice");
params.put("age", 30);
stmt.bind(params).execute();
// Bind with list (positional binding with indices)
stmt.bind(Arrays.asList("Alice", 30)).execute();
// Bind with varargs
stmt.bind("Alice", 30).execute();Statement for adding documents to a collection.
package com.mysql.cj.xdevapi;
public interface AddStatement extends Statement<AddStatement, AddResult> {
// Add documents
AddStatement add(String jsonString);
AddStatement add(DbDoc... docs);
AddStatement add(String... jsonStrings);
AddStatement add(Map<String, ?> docMap);
// Upsert support (used internally by Collection.addOrReplaceOne)
boolean isUpsert();
AddStatement setUpsert(boolean upsert);
// Execute statement
AddResult execute();
}
public class AddStatementImpl extends FilterableStatement<AddStatement, AddResult>
implements AddStatement {
// Implementation
public AddStatement add(DbDoc... docs);
public AddStatement add(String... jsonStrings);
public AddStatement add(Map<String, ?> docMap);
public AddResult execute();
}
public interface AddResult extends Result {
// Get generated document IDs
List<String> getGeneratedIds();
// Get affected items count
long getAffectedItemsCount();
// Get warnings
int getWarningsCount();
Iterator<Warning> getWarnings();
}
public class AddResultImpl implements AddResult {
public List<String> getGeneratedIds();
public long getAffectedItemsCount();
public int getWarningsCount();
public Iterator<Warning> getWarnings();
}Usage:
Collection users = schema.getCollection("users");
// Add single document
AddResult result = users.add("{\"name\": \"Alice\", \"age\": 30}").execute();
System.out.println("Generated IDs: " + result.getGeneratedIds());
// Add multiple documents
DbDoc doc1 = users.newDoc().add("name", new JsonString().setValue("Bob")).add("age", new JsonNumber().setValue("25"));
DbDoc doc2 = users.newDoc().add("name", new JsonString().setValue("Charlie")).add("age", new JsonNumber().setValue("35"));
AddResult result2 = users.add(doc1, doc2).execute();
// Add from map
Map<String, Object> userMap = new HashMap<>();
userMap.put("name", "David");
userMap.put("age", 28);
users.add(userMap).execute();Statement for finding documents in a collection.
package com.mysql.cj.xdevapi;
public interface FindStatement extends Statement<FindStatement, DocResult> {
// Projection
FindStatement fields(String... projection);
FindStatement fields(Expression projection);
// Grouping
FindStatement groupBy(String... fields);
FindStatement having(String having);
// Ordering
FindStatement orderBy(String... sortFields);
FindStatement sort(String... sortFields);
// Limiting
FindStatement limit(long numberOfRows);
FindStatement offset(long numberOfRows);
/**
* @deprecated Deprecated in Connector/J 8.0.12, use {@link #offset(long)} instead.
*/
@Deprecated
default FindStatement skip(long limitOffset) {
return offset(limitOffset);
}
// Locking
FindStatement lockShared();
FindStatement lockShared(Statement.LockContention lockContention);
FindStatement lockExclusive();
FindStatement lockExclusive(Statement.LockContention lockContention);
// Binding
FindStatement bind(String name, Object value);
FindStatement bind(Map<String, Object> values);
// Execution
DocResult execute();
}
public class FindStatementImpl extends FilterableStatement<FindStatement, DocResult>
implements FindStatement {
public FindStatement fields(String... projection);
public FindStatement fields(Expression projection);
public FindStatement groupBy(String... fields);
public FindStatement having(String having);
public FindStatement orderBy(String... sortFields);
public FindStatement sort(String... sortFields);
public FindStatement limit(long numberOfRows);
public FindStatement offset(long numberOfRows);
public FindStatement lockShared();
public FindStatement lockShared(Statement.LockContention lockContention);
public FindStatement lockExclusive();
public FindStatement lockExclusive(Statement.LockContention lockContention);
public FindStatement bind(String name, Object value);
public FindStatement bind(Map<String, Object> values);
public DocResult execute();
}
public interface DocResult extends FetchResult<DbDoc>, Iterator<DbDoc> {
// Iteration
boolean hasNext();
DbDoc next();
// Fetch operations
DbDoc fetchOne();
List<DbDoc> fetchAll();
int count();
// Warnings
int getWarningsCount();
Iterator<Warning> getWarnings();
}
public class DocResultImpl implements DocResult {
public boolean hasNext();
public DbDoc next();
public DbDoc fetchOne();
public List<DbDoc> fetchAll();
public int count();
public int getWarningsCount();
public Iterator<Warning> getWarnings();
}Usage:
Collection users = schema.getCollection("users");
// Simple find
DocResult result = users.find().execute();
while (result.hasNext()) {
DbDoc doc = result.next();
System.out.println(doc.toString());
}
// Find with condition
DocResult result2 = users.find("age > :minAge")
.bind("minAge", 25)
.execute();
// Find with projection
DocResult result3 = users.find("age > 25")
.fields("name", "age")
.execute();
// Find with ordering and limiting
DocResult result4 = users.find()
.orderBy("age DESC")
.limit(10)
.execute();
// Find with grouping
DocResult result5 = users.find()
.fields("age", "COUNT(*) as count")
.groupBy("age")
.having("count > 1")
.execute();
// Find with locking
session.startTransaction();
DocResult result6 = users.find("_id = :id")
.bind("id", "someId")
.lockExclusive()
.execute();
// Modify locked document
session.commit();
// Fetch all at once
List<DbDoc> allDocs = users.find().execute().fetchAll();Statement for modifying documents in a collection.
package com.mysql.cj.xdevapi;
public interface ModifyStatement extends Statement<ModifyStatement, Result> {
// Modification operations
ModifyStatement set(String docPath, Object value);
ModifyStatement change(String docPath, Object value);
ModifyStatement unset(String... fields);
ModifyStatement arrayInsert(String docPath, Object value);
ModifyStatement arrayAppend(String docPath, Object value);
ModifyStatement patch(DbDoc patch);
ModifyStatement patch(String jsonPatch);
// Ordering and limiting
ModifyStatement sort(String... sortFields);
ModifyStatement limit(long numberOfRows);
// Binding
ModifyStatement bind(String name, Object value);
ModifyStatement bind(Map<String, Object> values);
// Execution
Result execute();
}
public class ModifyStatementImpl extends FilterableStatement<ModifyStatement, Result>
implements ModifyStatement {
public ModifyStatement set(String docPath, Object value);
public ModifyStatement change(String docPath, Object value);
public ModifyStatement unset(String... fields);
public ModifyStatement arrayInsert(String docPath, Object value);
public ModifyStatement arrayAppend(String docPath, Object value);
public ModifyStatement patch(DbDoc patch);
public ModifyStatement patch(String jsonPatch);
public ModifyStatement sort(String... sortFields);
public ModifyStatement limit(long numberOfRows);
public ModifyStatement bind(String name, Object value);
public ModifyStatement bind(Map<String, Object> values);
public Result execute();
}
public enum UpdateType {
SET,
ITEM_REMOVE,
ITEM_SET,
ITEM_REPLACE,
ITEM_MERGE,
ARRAY_INSERT,
ARRAY_APPEND,
MERGE_PATCH;
}
public class UpdateSpec {
public UpdateSpec(UpdateType type, String path);
public UpdateSpec setValue(Object value);
public UpdateType getUpdateType();
public String getSource();
public Object getValue();
}Usage:
Collection users = schema.getCollection("users");
// Set field value
users.modify("_id = :id")
.set("age", 31)
.bind("id", "someId")
.execute();
// Unset field
users.modify("_id = :id")
.unset("middleName")
.bind("id", "someId")
.execute();
// Change field value (only if it exists)
users.modify("age > 25")
.change("status", "active")
.execute();
// Array operations
users.modify("_id = :id")
.arrayAppend("hobbies", "reading")
.bind("id", "someId")
.execute();
users.modify("_id = :id")
.arrayInsert("hobbies[0]", "coding")
.bind("id", "someId")
.execute();
// Patch document
DbDoc patch = new DbDocImpl();
patch.add("age", new JsonNumber().setValue("32"));
patch.add("city", new JsonString().setValue("New York"));
users.modify("_id = :id")
.patch(patch)
.bind("id", "someId")
.execute();
// Multiple modifications
users.modify("age > :minAge")
.set("status", "verified")
.set("lastUpdated", Expression.expr("NOW()"))
.bind("minAge", 18)
.limit(100)
.execute();
// Use expression
users.modify("_id = :id")
.set("visits", Expression.expr("visits + 1"))
.bind("id", "someId")
.execute();Statement for removing documents from a collection.
package com.mysql.cj.xdevapi;
public interface RemoveStatement extends Statement<RemoveStatement, Result> {
// Ordering and limiting
RemoveStatement sort(String... sortFields);
RemoveStatement limit(long numberOfRows);
// Binding
RemoveStatement bind(String name, Object value);
RemoveStatement bind(Map<String, Object> values);
// Execution
Result execute();
}
public class RemoveStatementImpl extends FilterableStatement<RemoveStatement, Result>
implements RemoveStatement {
public RemoveStatement sort(String... sortFields);
public RemoveStatement limit(long numberOfRows);
public RemoveStatement bind(String name, Object value);
public RemoveStatement bind(Map<String, Object> values);
public Result execute();
}
public interface Result {
long getAffectedItemsCount();
int getWarningsCount();
Iterator<Warning> getWarnings();
}Usage:
Collection users = schema.getCollection("users");
// Remove with condition
Result result = users.remove("age < :minAge")
.bind("minAge", 18)
.execute();
System.out.println("Removed: " + result.getAffectedItemsCount());
// Remove with limit
users.remove("status = 'inactive'")
.limit(10)
.execute();
// Remove with sorting
users.remove("age > 65")
.sort("age DESC")
.limit(5)
.execute();
// Remove all matching
users.remove("verified = false").execute();Statement for inserting rows into a table.
package com.mysql.cj.xdevapi;
public interface InsertStatement extends Statement<InsertStatement, InsertResult> {
// Add values
InsertStatement values(Object... values);
InsertStatement values(List<Object> values);
// Execution
InsertResult execute();
}
public class InsertStatementImpl implements InsertStatement {
public InsertStatement values(Object... values);
public InsertStatement values(List<Object> values);
public InsertResult execute();
}
public interface InsertResult extends Result {
Long getAutoIncrementValue();
long getAffectedItemsCount();
int getWarningsCount();
Iterator<Warning> getWarnings();
}
public class InsertResultImpl implements InsertResult {
public Long getAutoIncrementValue();
public long getAffectedItemsCount();
public int getWarningsCount();
public Iterator<Warning> getWarnings();
}
public class InsertParams {
// Helper class for collecting insert parameters
public InsertParams(List<String> fields);
public void addRow(List<Object> row);
public List<String> getFields();
public List<List<Object>> getRows();
}Usage:
Table employees = schema.getTable("employees");
// Insert single row
InsertResult result = employees.insert("name", "age", "department")
.values("Alice", 30, "Engineering")
.execute();
System.out.println("Auto-increment ID: " + result.getAutoIncrementValue());
// Insert multiple rows
employees.insert("name", "age", "department")
.values("Bob", 25, "Sales")
.values("Charlie", 35, "Marketing")
.values("David", 28, "Engineering")
.execute();
// Insert with nulls
employees.insert("name", "age", "department")
.values("Eve", 32, null)
.execute();
// Insert from list
List<Object> row = Arrays.asList("Frank", 29, "IT");
employees.insert("name", "age", "department")
.values(row)
.execute();Statement for selecting rows from a table.
package com.mysql.cj.xdevapi;
public interface SelectStatement extends Statement<SelectStatement, RowResult> {
// Filtering
SelectStatement where(String searchCondition);
// Grouping
SelectStatement groupBy(String... fields);
SelectStatement having(String having);
// Ordering
SelectStatement orderBy(String... sortFields);
// Limiting
SelectStatement limit(long numberOfRows);
SelectStatement offset(long numberOfRows);
// Locking
SelectStatement lockShared();
SelectStatement lockShared(Statement.LockContention lockContention);
SelectStatement lockExclusive();
SelectStatement lockExclusive(Statement.LockContention lockContention);
// Binding
SelectStatement bind(String name, Object value);
SelectStatement bind(Map<String, Object> values);
// Execution
RowResult execute();
// Filter parameters (internal use)
FilterParams getFilterParams();
}
public class SelectStatementImpl implements SelectStatement {
public SelectStatement where(String searchCondition);
public SelectStatement groupBy(String... fields);
public SelectStatement having(String having);
public SelectStatement orderBy(String... sortFields);
public SelectStatement limit(long numberOfRows);
public SelectStatement offset(long numberOfRows);
public SelectStatement lockShared();
public SelectStatement lockShared(Statement.LockContention lockContention);
public SelectStatement lockExclusive();
public SelectStatement lockExclusive(Statement.LockContention lockContention);
public SelectStatement bind(String name, Object value);
public SelectStatement bind(Map<String, Object> values);
public RowResult execute();
}
public interface RowResult extends FetchResult<Row>, Iterator<Row> {
// Iteration
boolean hasNext();
Row next();
// Fetch operations
Row fetchOne();
List<Row> fetchAll();
int count();
// Metadata
int getColumnCount();
List<Column> getColumns();
List<String> getColumnNames();
// Warnings
int getWarningsCount();
Iterator<Warning> getWarnings();
}
public class RowResultImpl implements RowResult {
public boolean hasNext();
public Row next();
public Row fetchOne();
public List<Row> fetchAll();
public int count();
public int getColumnCount();
public List<Column> getColumns();
public List<String> getColumnNames();
public int getWarningsCount();
public Iterator<Warning> getWarnings();
}Usage:
Table employees = schema.getTable("employees");
// Simple select
RowResult result = employees.select("name", "age", "department").execute();
while (result.hasNext()) {
Row row = result.next();
System.out.println(row.getString("name") + " - " + row.getInt("age"));
}
// Select with condition
RowResult result2 = employees.select("*")
.where("age > :minAge AND department = :dept")
.bind("minAge", 25)
.bind("dept", "Engineering")
.execute();
// Select with ordering and limiting
RowResult result3 = employees.select("name", "salary")
.where("department = 'Sales'")
.orderBy("salary DESC")
.limit(10)
.execute();
// Select with grouping
RowResult result4 = employees.select("department", "COUNT(*) as count", "AVG(salary) as avg_salary")
.groupBy("department")
.having("count > 5")
.execute();
// Select with offset
RowResult result5 = employees.select("*")
.orderBy("id")
.limit(20)
.offset(40) // Skip first 40 rows
.execute();
// Get column metadata
List<Column> columns = result.getColumns();
for (Column col : columns) {
System.out.println(col.getColumnName() + " - " + col.getType());
}Statement for updating rows in a table.
package com.mysql.cj.xdevapi;
public interface UpdateStatement extends Statement<UpdateStatement, Result> {
// Set field values
UpdateStatement set(String field, Object value);
// Filtering
UpdateStatement where(String searchCondition);
// Ordering and limiting
UpdateStatement orderBy(String... sortFields);
UpdateStatement limit(long numberOfRows);
// Binding
UpdateStatement bind(String name, Object value);
UpdateStatement bind(Map<String, Object> values);
// Execution
Result execute();
}
public class UpdateStatementImpl implements UpdateStatement {
public UpdateStatement set(String field, Object value);
public UpdateStatement where(String searchCondition);
public UpdateStatement orderBy(String... sortFields);
public UpdateStatement limit(long numberOfRows);
public UpdateStatement bind(String name, Object value);
public UpdateStatement bind(Map<String, Object> values);
public Result execute();
}
public class UpdateParams {
// Helper class for collecting update parameters
public UpdateParams();
public void addField(String field, Object value);
public Map<String, Object> getFields();
}
public class UpdateResult implements Result {
public long getAffectedItemsCount();
public int getWarningsCount();
public Iterator<Warning> getWarnings();
}Usage:
Table employees = schema.getTable("employees");
// Update with condition
Result result = employees.update()
.set("salary", 55000)
.where("name = :name")
.bind("name", "Alice")
.execute();
System.out.println("Updated: " + result.getAffectedItemsCount());
// Update multiple fields
employees.update()
.set("salary", 60000)
.set("department", "Senior Engineering")
.where("age > :minAge AND department = :dept")
.bind("minAge", 30)
.bind("dept", "Engineering")
.execute();
// Update with limit
employees.update()
.set("bonus", 1000)
.where("performance = 'excellent'")
.limit(10)
.execute();
// Update with expression
employees.update()
.set("salary", Expression.expr("salary * 1.1"))
.where("department = 'Sales'")
.execute();Statement for deleting rows from a table.
package com.mysql.cj.xdevapi;
public interface DeleteStatement extends Statement<DeleteStatement, Result> {
// Filtering
DeleteStatement where(String searchCondition);
// Ordering and limiting
DeleteStatement orderBy(String... sortFields);
DeleteStatement limit(long numberOfRows);
// Binding
DeleteStatement bind(String name, Object value);
DeleteStatement bind(Map<String, Object> values);
// Execution
Result execute();
}
public class DeleteStatementImpl implements DeleteStatement {
public DeleteStatement where(String searchCondition);
public DeleteStatement orderBy(String... sortFields);
public DeleteStatement limit(long numberOfRows);
public DeleteStatement bind(String name, Object value);
public DeleteStatement bind(Map<String, Object> values);
public Result execute();
}Usage:
Table employees = schema.getTable("employees");
// Delete with condition
Result result = employees.delete()
.where("age > :maxAge")
.bind("maxAge", 65)
.execute();
System.out.println("Deleted: " + result.getAffectedItemsCount());
// Delete with limit
employees.delete()
.where("status = 'inactive'")
.limit(10)
.execute();
// Delete with ordering
employees.delete()
.where("department = 'Sales'")
.orderBy("hire_date")
.limit(5)
.execute();
// Delete all matching
employees.delete()
.where("terminated = true")
.execute();Base interfaces for statement building.
package com.mysql.cj.xdevapi;
public interface Statement<STMT_T, RES_T> {
// Execute statement
RES_T execute();
}
public interface FetchResult<T> {
// Fetch operations
T fetchOne();
List<T> fetchAll();
int count();
}
/**
* Lock contention options defined as a nested enum in the Statement interface.
* Use as Statement.LockContention.DEFAULT, Statement.LockContention.NOWAIT, etc.
*/
public static enum Statement.LockContention {
DEFAULT, // Wait until the row lock is released
NOWAIT, // Fail with error if row is locked
SKIP_LOCKED // Remove locked rows from result set
}Abstract base class for statements with filtering capabilities.
package com.mysql.cj.xdevapi;
public abstract class FilterableStatement<STMT_T, RES_T> implements Statement<STMT_T, RES_T> {
// Subclasses implement specific filtering logic
}
public abstract class PreparableStatement<RES_T> {
// Base class for statements that can be prepared
// (Future enhancement for prepared statement support)
}Install with Tessl CLI
npx tessl i tessl/maven-com-mysql--mysql-connector-j