メインコンテンツまでスキップ
バージョン: 3.14

プリミティブ CRUD インターフェースを介して非トランザクションストレージ操作を実行する

注記

このページは英語版のページが機械翻訳されたものです。英語版との間に矛盾または不一致がある場合は、英語版を正としてください。

このページでは、プリミティブ CRUD インターフェース (Storage API とも呼ばれる) を通じて非トランザクションストレージ操作を実行する方法について説明します。このガイドでは、読者が ScalarDB について高度な知識を持っていることを前提としています。

既存のストレージおよびデータベースシステム上でストレージに依存しない、またはデータベースに依存しない ACID トランザクションを実現するためのキーの1つは、ScalarDB が提供するストレージ抽象化機能です。ストレージ抽象化は、データモデル と、データモデルに基づいて操作を発行する API (Storage API) を定義します。

ほとんどの場合、Transactional API を使用することになりますが、別のオプションとして Storage API を使用することもできます。

Storage API を使用する利点は次のとおりです。

  • トランザクション API と同様に、基盤となるストレージ実装についてあまり気にせずにアプリケーションコードを作成できます。
  • アプリケーション内の一部のデータに対してトランザクションが必要ない場合は、Storage API を使用してトランザクションを部分的に回避し、実行を高速化できます。
警告

ストレージ API を直接使用したり、トランザクション API とストレージ API を混在させたりした場合、予期しない動作が発生する可能性があります。たとえば、ストレージ API はトランザクション機能を提供できないため、操作の実行時に障害が発生すると、API によって異常やデータの不整合が発生する可能性があります。

したがって、ストレージ API の使用には 非常に 注意し、何をしているのかを正確に理解している場合にのみ使用してください。

ストレージ API の例

このセクションでは、基本的な電子マネーアプリケーションでストレージ API を使用する方法について説明します。

警告

この例では電子マネーアプリケーションが簡略化されており、実稼働環境には適していません。

ScalarDB の設定

開始する前に、ScalarDB をはじめよう で説明されているのと同じ方法で ScalarDB を設定する必要があります。

これを念頭に置いて、このストレージ API の例では、設定ファイル scalardb.properties が存在することを前提としています。

データベーススキーマの設定

アプリケーションでデータベーススキーマ (データを整理する方法) を定義する必要があります。サポートされているデータ型の詳細については、ScalarDB と他のデータベース間のデータ型マッピングを参照してください。

この例では、scalardb/docs/getting-started ディレクトリに emoney-storage.json という名前のファイルを作成します。次に、次の JSON コードを追加してスキーマを定義します。

注記

次の JSON では、transaction フィールドが false に設定されており、このテーブルを Storage API で使用する必要があることを示しています。

{
"emoney.account": {
"transaction": false,
"partition-key": [
"id"
],
"clustering-key": [],
"columns": {
"id": "TEXT",
"balance": "INT"
}
}
}

スキーマを適用するには、ScalarDB Releases ページに移動し、使用している ScalarDB のバージョンに一致する ScalarDB Schema Loader を getting-started フォルダーにダウンロードします。

次に、<VERSION> をダウンロードした ScalarDB Schema Loader のバージョンに置き換えて、次のコマンドを実行します。

java -jar scalardb-schema-loader-<VERSION>.jar --config scalardb.properties -f emoney-storage.json

サンプルコード

以下は、Storage API を使用する電子マネーアプリケーションのサンプルソースコードです。

警告

前述のとおり、Storage API はトランザクション機能を提供できないため、操作の実行中に障害が発生すると、API によって異常やデータの不整合が発生する可能性があります。したがって、Storage API の使用には十分注意し、何をしているのかを正確に理解している場合にのみ使用してください。

public class ElectronicMoney {

private static final String SCALARDB_PROPERTIES =
System.getProperty("user.dir") + File.separator + "scalardb.properties";
private static final String NAMESPACE = "emoney";
private static final String TABLENAME = "account";
private static final String ID = "id";
private static final String BALANCE = "balance";

private final DistributedStorage storage;

public ElectronicMoney() throws IOException {
StorageFactory factory = StorageFactory.create(SCALARDB_PROPERTIES);
storage = factory.getStorage();
}

public void charge(String id, int amount) throws ExecutionException {
// Retrieve the current balance for id
Get get =
Get.newBuilder()
.namespace(NAMESPACE)
.table(TABLENAME)
.partitionKey(Key.ofText(ID, id))
.build();
Optional<Result> result = storage.get(get);

// Calculate the balance
int balance = amount;
if (result.isPresent()) {
int current = result.get().getInt(BALANCE);
balance += current;
}

// Update the balance
Put put =
Put.newBuilder()
.namespace(NAMESPACE)
.table(TABLENAME)
.partitionKey(Key.ofText(ID, id))
.intValue(BALANCE, balance)
.build();
storage.put(put);
}

public void pay(String fromId, String toId, int amount) throws ExecutionException {
// Retrieve the current balances for ids
Get fromGet =
Get.newBuilder()
.namespace(NAMESPACE)
.table(TABLENAME)
.partitionKey(Key.ofText(ID, fromId))
.build();
Get toGet =
Get.newBuilder()
.namespace(NAMESPACE)
.table(TABLENAME)
.partitionKey(Key.ofText(ID, toId))
.build();
Optional<Result> fromResult = storage.get(fromGet);
Optional<Result> toResult = storage.get(toGet);

// Calculate the balances (it assumes that both accounts exist)
int newFromBalance = fromResult.get().getInt(BALANCE) - amount;
int newToBalance = toResult.get().getInt(BALANCE) + amount;
if (newFromBalance < 0) {
throw new RuntimeException(fromId + " doesn't have enough balance.");
}

// Update the balances
Put fromPut =
Put.newBuilder()
.namespace(NAMESPACE)
.table(TABLENAME)
.partitionKey(Key.ofText(ID, fromId))
.intValue(BALANCE, newFromBalance)
.build();
Put toPut =
Put.newBuilder()
.namespace(NAMESPACE)
.table(TABLENAME)
.partitionKey(Key.ofText(ID, toId))
.intValue(BALANCE, newToBalance)
.build();
storage.put(fromPut);
storage.put(toPut);
}

public int getBalance(String id) throws ExecutionException {
// Retrieve the current balances for id
Get get =
Get.newBuilder()
.namespace(NAMESPACE)
.table(TABLENAME)
.partitionKey(Key.ofText(ID, id))
.build();
Optional<Result> result = storage.get(get);

int balance = -1;
if (result.isPresent()) {
balance = result.get().getInt(BALANCE);
}
return balance;
}

public void close() {
storage.close();
}
}

ストレージ API ガイド

ストレージ API は、管理 API と CRUD API で設定されています。

管理 API

このセクションで説明するように、管理操作をプログラムで実行できます。

注記

管理操作を実行するために使用できる別の方法は、Schema Loader を使用することです。

DistributedStorageAdmin インスタンスを取得する

管理操作を実行するには、まず DistributedStorageAdmin インスタンスを取得する必要があります。次のように StorageFactory から DistributedStorageAdmin インスタンスを取得できます。

StorageFactory storageFactory = StorageFactory.create("<CONFIGURATION_FILE_PATH>");
DistributedStorageAdmin admin = storageFactory.getStorageAdmin();

設定の詳細については、ScalarDB 設定を参照してください。

すべての管理操作を実行したら、次のように DistributedStorageAdmin インスタンスを閉じる必要があります。

admin.close();

名前空間を作成する

テーブルは1つの名前空間に属するため、テーブルを作成する前に名前空間を作成する必要があります。

名前空間は次のように作成できます。

// Create the namespace "ns". If the namespace already exists, an exception will be thrown.
admin.createNamespace("ns");

// Create the namespace only if it does not already exist.
boolean ifNotExists = true;
admin.createNamespace("ns", ifNotExists);

// Create the namespace with options.
Map<String, String> options = ...;
admin.createNamespace("ns", options);

作成オプションの詳細については、作成オプションを参照してください。

テーブルを作成する

テーブルを作成するときは、テーブルメタデータを定義してからテーブルを作成する必要があります。

テーブルメタデータを定義するには、TableMetadata を使用できます。次に、テーブルの列、パーティションキー、クラスタリングキー (クラスタリング順序を含む)、およびセカンダリインデックスを定義する方法を示します。

// Define the table metadata.
TableMetadata tableMetadata =
TableMetadata.newBuilder()
.addColumn("c1", DataType.INT)
.addColumn("c2", DataType.TEXT)
.addColumn("c3", DataType.BIGINT)
.addColumn("c4", DataType.FLOAT)
.addColumn("c5", DataType.DOUBLE)
.addPartitionKey("c1")
.addClusteringKey("c2", Scan.Ordering.Order.DESC)
.addClusteringKey("c3", Scan.Ordering.Order.ASC)
.addSecondaryIndex("c4")
.build();

ScalarDB のデータモデルの詳細については、データモデルを参照してください。

次に、次のようにテーブルを作成します。

// Create the table "ns.tbl". If the table already exists, an exception will be thrown.
admin.createTable("ns", "tbl", tableMetadata);

// Create the table only if it does not already exist.
boolean ifNotExists = true;
admin.createTable("ns", "tbl", tableMetadata, ifNotExists);

// Create the table with options.
Map<String, String> options = ...;
admin.createTable("ns", "tbl", tableMetadata, options);

セカンダリインデックスを作成する

セカンダリインデックスは次のように作成できます。

// Create a secondary index on column "c5" for table "ns.tbl". If a secondary index already exists, an exception will be thrown.
admin.createIndex("ns", "tbl", "c5");

// Create the secondary index only if it does not already exist.
boolean ifNotExists = true;
admin.createIndex("ns", "tbl", "c5", ifNotExists);

// Create the secondary index with options.
Map<String, String> options = ...;
admin.createIndex("ns", "tbl", "c5", options);

テーブルに新しい列を追加する

次のように、テーブルに新しい非パーティションキー列を追加できます。

// Add a new column "c6" with the INT data type to the table "ns.tbl".
admin.addNewColumnToTable("ns", "tbl", "c6", DataType.INT)
警告

テーブルに新しい列を追加する場合は、基盤となるストレージによって実行時間が大きく異なる可能性があるため、慎重に検討する必要があります。それに応じて計画を立て、特にデータベースが本番環境で実行されている場合は、次の点を考慮してください。

  • Cosmos DB for NoSQL および DynamoDB の場合: テーブルスキーマは変更されないため、列の追加はほぼ瞬時に行われます。別のテーブルに格納されているテーブルメタデータのみが更新されます。
  • Cassandra の場合: 列を追加すると、スキーマメタデータのみが更新され、既存のスキーマレコードは変更されません。クラスタートポロジが実行時間の主な要因です。スキーマメタデータの変更は、ゴシッププロトコルを介して各クラスターノードに共有されます。このため、クラスターが大きいほど、すべてのノードが更新されるまでの時間が長くなります。
  • リレーショナルデータベース (MySQL、Oracle など) の場合: 列の追加は実行にそれほど時間がかかりません。

テーブルを切り捨てる

テーブルを切り捨てるには、次のようにします。

// Truncate the table "ns.tbl".
admin.truncateTable("ns", "tbl");

セカンダリインデックスを削除する

セカンダリインデックスは次のように削除できます。

// Drop the secondary index on column "c5" from table "ns.tbl". If the secondary index does not exist, an exception will be thrown.
admin.dropIndex("ns", "tbl", "c5");

// Drop the secondary index only if it exists.
boolean ifExists = true;
admin.dropIndex("ns", "tbl", "c5", ifExists);

テーブルを削除する

テーブルを削除するには、次のようにします。

// Drop the table "ns.tbl". If the table does not exist, an exception will be thrown.
admin.dropTable("ns", "tbl");

// Drop the table only if it exists.
boolean ifExists = true;
admin.dropTable("ns", "tbl", ifExists);

名前空間を削除する

名前空間を削除するには、次のようにします。

// Drop the namespace "ns". If the namespace does not exist, an exception will be thrown.
admin.dropNamespace("ns");

// Drop the namespace only if it exists.
boolean ifExists = true;
admin.dropNamespace("ns", ifExists);

既存の名前空間を取得する

既存の名前空間は次のように取得できます。

Set<String> namespaces = admin.getNamespaceNames();

名前空間のテーブルを取得する

名前空間のテーブルは次のように取得できます。

// Get the tables of the namespace "ns".
Set<String> tables = admin.getNamespaceTableNames("ns");

テーブルメタデータを取得する

テーブルメタデータは次のように取得できます。

// Get the table metadata for "ns.tbl".
TableMetadata tableMetadata = admin.getTableMetadata("ns", "tbl");

名前空間を修復する

名前空間が不明な状態の場合 (名前空間が基盤となるストレージに存在するが ScalarDB メタデータが存在しない、またはその逆)、このメソッドは必要に応じて名前空間とそのメタデータを再作成します。

名前空間は次のように修復できます。

// Repair the namespace "ns" with options.
Map<String, String> options = ...;
admin.repairNamespace("ns", options);

テーブルを修復する

テーブルが不明な状態の場合 (テーブルは基盤となるストレージに存在するが ScalarDB メタデータは存在しない、またはその逆)、このメソッドは必要に応じてテーブル、そのセカンダリインデックス、およびそのメタデータを再作成します。

テーブルは次のように修復できます。

// Repair the table "ns.tbl" with options.
TableMetadata tableMetadata =
TableMetadata.newBuilder()
...
.build();
Map<String, String> options = ...;
admin.repairTable("ns", "tbl", tableMetadata, options);

最新の ScalarDB API をサポートするように環境をアップグレードする

ScalarDB API の最新バージョンをサポートするように ScalarDB 環境をアップグレードできます。通常、リリースノートに記載されているように、アプリケーション環境が使用する ScalarDB バージョンを更新した後、このメソッドを実行する必要があります。

// Upgrade the ScalarDB environment.
Map<String, String> options = ...;
admin.upgrade(options);

CRUD 操作を実装する

次のセクションでは、CRUD 操作について説明します。

DistributedStorage インスタンスを取得する

Storage API で CRUD 操作を実行するには、DistributedStorage インスタンスを取得する必要があります。

インスタンスは次のように取得できます。

StorageFactory storageFactory = StorageFactory.create("<CONFIGURATION_FILE_PATH>");
DistributedStorage storage = storageFactory.getStorage();

すべての CRUD 操作を実行したら、次のように DistributedStorage インスタンスを閉じる必要があります。

storage.close();

Get 操作

Get は、主キーで指定された単一のレコードを取得する操作です。

まず Get オブジェクトを作成し、次に次のように storage.get() メソッドを使用してオブジェクトを実行する必要があります。

// Create a `Get` operation.
Key partitionKey = Key.ofInt("c1", 10);
Key clusteringKey = Key.of("c2", "aaa", "c3", 100L);

Get get =
Get.newBuilder()
.namespace("ns")
.table("tbl")
.partitionKey(partitionKey)
.clusteringKey(clusteringKey)
.projections("c1", "c2", "c3", "c4")
.build();

// Execute the `Get` operation.
Optional<Result> result = storage.get(get);

また、投影を指定して、返される列を選択することもできます。

Key オブジェクトの構築方法の詳細については、キーの構築を参照してください。また、Result オブジェクトの処理方法の詳細については、Result オブジェクトの処理を参照してください。

一貫性レベルを指定する

Storage API の各操作 (GetScanPutDelete) で一貫性レベルを次のように指定できます。

Get get =
Get.newBuilder()
.namespace("ns")
.table("tbl")
.partitionKey(partitionKey)
.clusteringKey(clusteringKey)
.consistency(Consistency.LINEARIZABLE) // Consistency level
.build();

次の表は、3つの一貫性レベルについて説明しています。

一貫性レベル説明
SEQUENTIAL順次一貫性は、基礎となるストレージ実装によってすべての操作が何らかの順次順序で実行されるようにされ、各プロセスの操作がこの順序で実行されることを前提としています。
EVENTUAL結果一貫性は、基礎となるストレージ実装によってすべての操作が最終的に実行されることを前提としています。
LINEARIZABLE線形化可能な一貫性は、基礎となるストレージ実装によって各操作が呼び出しから完了までの間のある時点でアトミックに実行されるようにされることを前提としています。
セカンダリインデックスを使用して Get を実行する

セカンダリインデックスを使用して Get 操作を実行できます。

パーティションキーを指定する代わりに、次のようにインデックスキー (インデックス付き列) を指定してセカンダリインデックスを使用できます。

// Create a `Get` operation by using a secondary index.
Key indexKey = Key.ofFloat("c4", 1.23F);

Get get =
Get.newBuilder()
.namespace("ns")
.table("tbl")
.indexKey(indexKey)
.projections("c1", "c2", "c3", "c4")
.build();

// Execute the `Get` operation.
Optional<Result> result = storage.get(get);
注記

結果に複数のレコードがある場合、storage.get() は例外をスローします。

Scan 操作

Scan は、パーティション内の複数のレコードを取得する操作です。Scan 操作では、クラスタリングキーの境界とクラスタリングキー列の順序を指定できます。

まず Scan オブジェクトを作成し、次に次のように storage.scan() メソッドを使用してオブジェクトを実行する必要があります。

// Create a `Scan` operation.
Key partitionKey = Key.ofInt("c1", 10);
Key startClusteringKey = Key.of("c2", "aaa", "c3", 100L);
Key endClusteringKey = Key.of("c2", "aaa", "c3", 300L);

Scan scan =
Scan.newBuilder()
.namespace("ns")
.table("tbl")
.partitionKey(partitionKey)
.start(startClusteringKey, true) // Include startClusteringKey
.end(endClusteringKey, false) // Exclude endClusteringKey
.projections("c1", "c2", "c3", "c4")
.orderings(Scan.Ordering.desc("c2"), Scan.Ordering.asc("c3"))
.limit(10)
.build();

// Execute the `Scan` operation.
Scanner scanner = storage.scan(scan);

クラスタリングキー境界を省略するか、start 境界または end 境界のいずれかを指定できます。orderings を指定しない場合は、テーブルの作成時に定義したクラスタリング順序で結果が並べられます。

さらに、projections を指定して返される列を選択し、limit を使用して Scan 操作で返されるレコードの数を指定できます。

Scanner オブジェクトの処理

Storage API の Scan 操作は Scanner オブジェクトを返します。

Scanner オブジェクトから結果を1つずつ取得する場合は、次のように one() メソッドを使用できます。

Optional<Result> result = scanner.one();

または、すべての結果のリストを取得する場合は、次のように all() メソッドを使用できます。

List<Result> results = scanner.all();

さらに、ScannerIterable を実装しているので、次のように for-each ループ内で Scanner を使用できます。

for (Result result : scanner) {
...
}

結果を取得した後は、Scanner オブジェクトを閉じることを忘れないでください。

scanner.close();

または、次のように try-with-resources を使用することもできます。

try (Scanner scanner = storage.scan(scan)) {
...
}
セカンダリインデックスを使用して Scan を実行する

セカンダリインデックスを使用して Scan 操作を実行できます。

パーティションキーを指定する代わりに、次のようにインデックスキー (インデックス付き列) を指定してセカンダリインデックスを使用できます。

// Create a `Scan` operation by using a secondary index.
Key indexKey = Key.ofFloat("c4", 1.23F);

Scan scan =
Scan.newBuilder()
.namespace("ns")
.table("tbl")
.indexKey(indexKey)
.projections("c1", "c2", "c3", "c4")
.limit(10)
.build();

// Execute the `Scan` operation.
Scanner scanner = storage.scan(scan);
注記

セカンダリインデックスを使用して、Scan でクラスタリングキーの境界と順序を指定することはできません。

パーティションキーを指定せずに Scan を実行して、テーブルのすべてのレコードを取得します

パーティションキーを指定せずに Scan 操作を実行できます。

ビルダーで partitionKey() メソッドを呼び出す代わりに、次のように all() メソッドを呼び出して、パーティションキーを指定せずにテーブルをスキャンできます。

// Create a `Scan` operation without specifying a partition key.
Key partitionKey = Key.ofInt("c1", 10);
Key startClusteringKey = Key.of("c2", "aaa", "c3", 100L);
Key endClusteringKey = Key.of("c2", "aaa", "c3", 300L);

Scan scan =
Scan.newBuilder()
.namespace("ns")
.table("tbl")
.all()
.projections("c1", "c2", "c3", "c4")
.limit(10)
.build();

// Execute the `Scan` operation.
Scanner scanner = storage.scan(scan);
注記

パーティションキーを指定せずに Scan でクラスタリングキーの境界と順序を指定することはできません。

Put 操作

Put は、主キーで指定されたレコードを配置する操作です。この操作はレコードの upsert 操作として動作し、レコードが存在する場合はレコードを更新し、レコードが存在しない場合はレコードを挿入します。

まず Put オブジェクトを作成し、次に次のように storage.put() メソッドを使用してオブジェクトを実行する必要があります。

// Create a `Put` operation.
Key partitionKey = Key.ofInt("c1", 10);
Key clusteringKey = Key.of("c2", "aaa", "c3", 100L);

Put put =
Put.newBuilder()
.namespace("ns")
.table("tbl")
.partitionKey(partitionKey)
.clusteringKey(clusteringKey)
.floatValue("c4", 1.23F)
.doubleValue("c5", 4.56)
.build();

// Execute the `Put` operation.
storage.put(put);

次のように null 値を持つレコードを配置することもできます。

Put put =
Put.newBuilder()
.namespace("ns")
.table("tbl")
.partitionKey(partitionKey)
.clusteringKey(clusteringKey)
.floatValue("c4", null)
.doubleValue("c5", null)
.build();
注記

Put 操作ビルダーで enableImplicitPreRead()disableImplicitPreRead()、または implicitPreReadEnabled() を指定した場合、それらは無視されます。

Delete 操作

Delete は、主キーで指定されたレコードを削除する操作です。

まず Delete オブジェクトを作成し、次に次のように storage.delete() メソッドを使用してオブジェクトを実行する必要があります。

// Create a `Delete` operation.
Key partitionKey = Key.ofInt("c1", 10);
Key clusteringKey = Key.of("c2", "aaa", "c3", 100L);

Delete delete =
Delete.newBuilder()
.namespace("ns")
.table("tbl")
.partitionKey(partitionKey)
.clusteringKey(clusteringKey)
.build();

// Execute the `Delete` operation.
storage.delete(delete);

条件付きの Put および Delete

条件をチェックするロジックを実装することで、操作を実行する前に満たす必要がある任意の条件 (たとえば、銀行口座の残高は0以上である必要があります) を記述できます。または、PutDelete などのミューテーション操作で単純な条件を記述することもできます。

Put または Delete 操作に条件が含まれている場合、指定された条件が満たされた場合にのみ操作が実行されます。操作の実行時に条件が満たされていない場合は、NoMutationException という例外がスローされます。

Put の条件

Storage API の Put 操作では、指定された条件が一致した場合にのみ Put 操作が実行されるようにする条件を指定できます。この操作は、条件が比較され、更新がアトミックに実行される比較とスワップの操作に似ています。

Put 操作では次のように条件を指定できます。

// Build a condition.
MutationCondition condition =
ConditionBuilder.putIf(ConditionBuilder.column("c4").isEqualToFloat(0.0F))
.and(ConditionBuilder.column("c5").isEqualToDouble(0.0))
.build();

Put put =
Put.newBuilder()
.namespace("ns")
.table("tbl")
.partitionKey(partitionKey)
.clusteringKey(clusteringKey)
.floatValue("c4", 1.23F)
.doubleValue("c5", 4.56)
.condition(condition) // condition
.build();

putIf 条件以外に、putIfExists および putIfNotExists 条件を次のように指定できます。

// Build a `putIfExists` condition.
MutationCondition putIfExistsCondition = ConditionBuilder.putIfExists();

// Build a `putIfNotExists` condition.
MutationCondition putIfNotExistsCondition = ConditionBuilder.putIfNotExists();
Delete の条件

Put 操作と同様に、Storage API の Delete 操作でも条件を指定できます。

Delete 操作では、次のように条件を指定できます。

// Build a condition.
MutationCondition condition =
ConditionBuilder.deleteIf(ConditionBuilder.column("c4").isEqualToFloat(0.0F))
.and(ConditionBuilder.column("c5").isEqualToDouble(0.0))
.build();

Delete delete =
Delete.newBuilder()
.namespace("ns")
.table("tbl")
.partitionKey(partitionKey)
.clusteringKey(clusteringKey)
.condition(condition) // condition
.build();

deleteIf 条件を使用するだけでなく、次のように deleteIfExists 条件を指定することもできます。

// Build a `deleteIfExists` condition.
MutationCondition deleteIfExistsCondition = ConditionBuilder.deleteIfExists();

ミューテート操作

ミューテートは、単一のパーティションで複数のミューテート (Put および Delete 操作) を実行する操作です。

まずミューテートオブジェクトを作成し、次に次のように storage.mutate() メソッドを使用してオブジェクトを実行する必要があります。

// Create `Put` and `Delete` operations.
Key partitionKey = Key.ofInt("c1", 10);

Key clusteringKeyForPut = Key.of("c2", "aaa", "c3", 100L);

Put put =
Put.newBuilder()
.namespace("ns")
.table("tbl")
.partitionKey(partitionKey)
.clusteringKey(clusteringKeyForPut)
.floatValue("c4", 1.23F)
.doubleValue("c5", 4.56)
.build();

Key clusteringKeyForDelete = Key.of("c2", "bbb", "c3", 200L);

Delete delete =
Delete.newBuilder()
.namespace("ns")
.table("tbl")
.partitionKey(partitionKey)
.clusteringKey(clusteringKeyForDelete)
.build();

// Execute the operations.
storage.mutate(Arrays.asList(put, delete));
注記

Mutate 操作では、単一のパーティションのミューテーションのみが受け入れられます。それ以外の場合は、例外がスローされます。

さらに、Mutate 操作で複数の条件を指定すると、すべての条件が一致した場合にのみ操作が実行されます。

CRUD 操作のデフォルト名前空間

すべての CRUD 操作のデフォルト名前空間は、ScalarDB 設定のプロパティを使用して設定できます。

scalar.db.default_namespace_name=<NAMESPACE_NAME>

名前空間を指定しない操作では、設定で設定されたデフォルトの名前空間が使用されます。

// This operation will target the default namespace.
Scan scanUsingDefaultNamespace =
Scan.newBuilder()
.table("tbl")
.all()
.build();
// This operation will target the "ns" namespace.
Scan scanUsingSpecifiedNamespace =
Scan.newBuilder()
.namespace("ns")
.table("tbl")
.all()
.build();