データテーブルのローカル トランザクション機能を有効にすると、指定したパーティションキー値に基づいてローカル トランザクションを作成し、ローカル トランザクション内のデータに対して読み取りおよび書き込み操作を実行できます。ローカル トランザクション機能を使用して、1 つ以上の行を読み書きするアトミック操作を実行できます。
シナリオ
ローカル トランザクション機能を使用すると、1 つ以上の行を読み書きするアトミック操作を実行できます。このセクションでは、この機能のサンプル シナリオについて説明します。
単純なシナリオ: データの読み取りと書き込み
次の 2 つの方法を使用して、読み取り、変更、書き込み (RMW) 操作を実行できます。2 つの方法にはそれぞれ特定の制限があります。
条件付き更新: 一度に 1 つの行を含む 1 つのリクエストのみを処理します。このメソッドを使用して、複数のデータ行を含むリクエストや、複数の書き込み操作を含むリクエストを処理することはできません。詳細については、条件付き更新を参照してください。
アトミック カウンター: 一度に 1 つの行を含む 1 つのリクエストのみを処理し、列値のインクリメントのみをサポートします。詳細については、アトミック カウンター機能の使用を参照してください。
前述の問題を解決するには、ローカル トランザクションを作成して、パーティションキー値で指定された範囲内のデータに対して RMW 操作を実行します。
StartLocalTransaction 操作を呼び出して、指定したパーティションキー値に基づいてローカル トランザクションを作成し、ローカル トランザクション ID を取得します。
GetRow または GetRange 操作を呼び出してデータを読み取ります。リクエストにはローカル トランザクション ID が含まれている必要があります。
クライアントでデータを変更します。
PutRow、UpdateRow、DeleteRow、または BatchWriteRow 操作を呼び出して、変更されたデータを書き戻します。リクエストにはローカル トランザクション ID が含まれている必要があります。
CommitTransaction 操作を呼び出して、ローカル トランザクションをコミットします。
複雑なシナリオ: メール管理
ローカル トランザクションを作成して、特定のユーザーのメールに対してアトミック操作を実行できます。
ローカル トランザクション機能を使用するには、データテーブルに 2 つのインデックステーブルを含めます。次の表は、データテーブルとインデックステーブルのプライマリキー列を示しています。[タイプ] 列は、データテーブルの行とインデックステーブルの行を識別するために使用されます。[IndexField] 列には、Folder インデックステーブルの $Folder フィールドと、SendTime インデックステーブルの $SendTime フィールドが格納されます。データテーブルの [IndexField] 列は空です。
テーブル | プライマリキー列 | |||
ユーザーID | タイプ | IndexField | メールID | |
データテーブル | ユーザー ID | "Main" | 該当なし | メール ID |
フォルダ インデックステーブル | ユーザー ID | "Folder" | $Folder | メール ID |
SendTime インデックステーブル | ユーザー ID | "SendTime" | $SendTime | メール ID |
具体的には、ローカル トランザクション機能を使用して、メールに対して次の操作を実行できます。
シナリオ 1: ユーザーが送信した最新の 100 件のメールを一覧表示する
ユーザー ID を使用してローカル トランザクションを作成し、ローカル トランザクション ID を取得します。
GetRange 操作を呼び出して、SendTime インデックステーブルから 100 件のメールをクエリします。リクエストにはローカル トランザクション ID が含まれている必要があります。
BatchGetRow 操作を呼び出して、データテーブルから 100 件のメールの詳細情報をクエリします。リクエストにはローカル トランザクション ID が含まれている必要があります。
CommitTransaction 操作を呼び出してローカル トランザクションをコミットするか、AbortTransaction 操作を呼び出してローカル トランザクションを中止します。
シナリオ 2: フォルダ内のすべてのメールを別のフォルダに転送する
ユーザー ID を使用してローカル トランザクションを作成し、ローカル トランザクション ID を取得します。
GetRange 操作を呼び出して、Folder インデックステーブルからメールをクエリします。リクエストにはローカル トランザクション ID が含まれている必要があります。
BatchWriteRow 操作を呼び出して、Folder インデックステーブルに書き込み操作を実行します。リクエストにはローカル トランザクション ID が含まれている必要があります。
メールが転送されるたびに、2 つの行に対して書き込み操作が実行されます。具体的には、元のフォルダを示す行が Folder インデックステーブルから削除され、新しいフォルダを示す行が Folder インデックステーブルに追加されます。
CommitTransaction 操作を呼び出して、ローカル トランザクションをコミットします。
シナリオ 3: フォルダ内の既読メールと未読メールの数をカウントする
ユーザー ID を使用してローカル トランザクションを作成し、ローカル トランザクション ID を取得します。
GetRange 操作を呼び出して、Folder インデックステーブルからメールをクエリします。リクエストにはローカル トランザクション ID が含まれている必要があります。
BatchGetRow 操作を呼び出して、データテーブルから各メールの既読ステータスをクエリします。
CommitTransaction 操作を呼び出してローカル トランザクションをコミットするか、AbortTransaction 操作を呼び出してローカル トランザクションを中止します。
このソリューションは最適ではありません。このシナリオでは、クエリを高速化するために、さらにインデックステーブルを追加できます。ローカル トランザクション機能により、データテーブルとインデックステーブル間のステータスの一貫性が確保されます。これにより、開発が簡素化されます。たとえば、このソリューションを使用してメールの数をカウントする場合、多数のメールを読み取る必要があります。これにより、オーバーヘッドが高くなります。オーバーヘッドを削減し、クエリを高速化するには、新しいインデックステーブルを使用して既読メールと未読メールの数を格納できます。
始める前に
管理対象のデータテーブルでローカル トランザクション機能が有効になっていることを確認してください。
ローカル トランザクション機能は招待制プレビューで利用可能です。デフォルトでは、この機能は無効になっています。ローカル トランザクション機能を使用するには、チケットを送信。
Tablestore SDK for Java V5.11.0 以降を使用している場合は、データテーブルの作成時にローカル トランザクション機能を有効にできます。詳細については、データテーブルの操作を参照してください。
使用上の注意
自動インクリメント プライマリキー列機能とローカル トランザクション機能を同時に使用することはできません。
ローカル トランザクションでの同時実行操作を制御するには、悲観的ロックが使用されます。
ローカル トランザクションの有効期間は最大 60 秒です。
ローカル トランザクションが 60 秒以内にコミットまたは中止されない場合、Tablestore サーバーはローカル トランザクションがタイムアウトしたと判断し、トランザクションを中止します。
タイムアウトエラーが返された場合でも、Tablestore サーバーでトランザクションが作成される場合があります。この場合、作成されたトランザクションがタイムアウトした後に、トランザクション作成リクエストを再送信できます。
ローカル トランザクションがコミットされていない場合、無効になる可能性があります。この場合、このトランザクションの操作を再試行してください。
ローカル トランザクション内のデータに対して書き込み操作が実行されない場合、コミット操作と中止操作は同じ効果があります。
Tablestore は、ローカル トランザクション内のデータに対する読み取りおよび書き込み操作に次の制限を課します。
ローカル トランザクション ID を使用して、トランザクションの作成に使用されたパーティションキー値に基づいて指定された範囲外のデータにアクセスすることはできません。
同じトランザクション内のすべての書き込みリクエストのパーティションキー値は、トランザクションの作成に使用されたパーティションキー値と同じである必要があります。この制限は、読み取りリクエストには適用されません。
ローカル トランザクションは、一度に 1 つのリクエストのみで使用できます。ローカル トランザクションが使用中の場合、同じローカル トランザクション ID を使用する他の操作は失敗します。
ローカル トランザクション内のデータに対する 2 つの連続した読み取りまたは書き込み操作の最大間隔は 60 秒です。
ローカル トランザクション内のデータに対して 60 秒以上読み取りまたは書き込み操作が実行されない場合、Tablestore サーバーはトランザクションがタイムアウトしたと判断し、トランザクションを中止します。
各トランザクションに最大 4 MB のデータを書き込むことができます。各トランザクションに書き込まれるデータ量は、通常の書き込みリクエストと同じ方法で計算されます。
セルにバージョン番号を指定しない場合、Tablestore サーバーは、トランザクションのコミット時ではなく、セルがトランザクションに書き込まれたときに、通常の方法でセルにバージョン番号を自動的に割り当てます。
BatchWriteRow リクエストにローカル トランザクション ID が含まれている場合、リクエスト内のすべての行は、ローカル トランザクション ID に一致するテーブルにのみ書き込むことができます。
ローカル トランザクションを使用する場合、ローカル トランザクションの作成基となったパーティションキー値のデータに書き込みロックが追加されます。ローカル トランザクション ID を含み、ローカル トランザクション内のデータの書き込みを開始する書き込みリクエストのみが成功します。他の非トランザクションリクエスト、または他のローカル トランザクションの ID を含み、ローカル トランザクション内のデータの書き込みを開始する書き込みリクエストは失敗します。ローカル トランザクション内のデータは、トランザクションがコミットまたは中止された場合、またはトランザクションがタイムアウトした場合にロック解除されます。
ローカル トランザクション ID を含む読み取りまたは書き込みリクエストが拒否された場合でも、ローカル トランザクションは有効なままです。再試行ルールを指定してリクエストを再送信するか、トランザクションを中止することができます。
API 操作
次の表は、ローカル トランザクションの管理に呼び出すことができる API 操作を示しています。
API 操作 | 説明 |
StartLocalTransaction | ローカル トランザクションを作成します。 |
CommitTransaction | ローカル トランザクションをコミットします。 |
AbortTransaction | ローカル トランザクションを中止します。 |
GetRow、PutRow、UpdateRow、DeleteRow、GetRange、または BatchWriteRow 操作を呼び出して、ローカル トランザクション内のデータを管理できます。詳細については、データの書き込み、データの読み取り、および データの削除を参照してください。
ローカル トランザクション内の行は、同じパーティションキー値を共有します。パーティションキーの詳細については、「プライマリキーと属性」トピックのパーティションキーセクションを参照してください。
ローカル トランザクション機能の使用
ローカル トランザクション機能を使用する前に、パーティションキー値に基づいてローカル トランザクションを作成する必要があります。その後、ローカル トランザクション内のデータに対して読み取りおよび書き込み操作を実行できます。操作の実行後、必要に応じてローカル トランザクションをコミットまたは中止できます。
ローカル トランザクションは、Tablestore SDK を使用してのみ管理できます。
次の Tablestore SDK がサポートされています: Tablestore SDK for Java、Tablestore SDK for Go、Tablestore SDK for Python、Tablestore SDK for Node.js、および Tablestore SDK for PHP。次の例は、ローカル トランザクション機能を使用して読み取りおよび書き込み操作を実行する方法を示しています。例では、Tablestore SDK for Java が使用されています。
ローカル トランザクション機能を使用してデータ行を書き込む
次のサンプルコードは、テーブル内の指定されたパーティションキー値に基づいてローカル トランザクションを作成する方法と、ローカル トランザクションにデータ行を書き込む方法を示しています。
private static void transactionPutRow(SyncClient client) {
// データテーブルの名前を指定します。
String tableName="<TABLE_NAME>";
// 指定したパーティションキー値に基づいてローカル トランザクションを作成します。
PrimaryKeyBuilder primaryKeyBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
// パーティションキーの列名、データ型、および列値を指定します。
primaryKeyBuilder.addPrimaryKeyColumn("pk1", PrimaryKeyValue.fromString("pkvalue"));
PrimaryKey primaryKey = primaryKeyBuilder.build();
// ローカル トランザクションを作成するためのリクエストを構築します。
StartLocalTransactionRequest request = new StartLocalTransactionRequest(tableName, primaryKey);
// ローカル トランザクションを作成するリクエストを開始し、ローカル トランザクション ID を取得します。
String txnId = client.startLocalTransaction(request).getTransactionID();
// ローカル トランザクションにデータ行を書き込みます。
// 行のプライマリキー情報を構成します。
PrimaryKeyBuilder primaryKeyBuilder1 = PrimaryKeyBuilder.createPrimaryKeyBuilder();
// プライマリキーの列名、データ型、および列値を指定します。テーブルのプライマリキーが複数のプライマリキー列で構成されている場合は、プライマリキー列に関する情報を順番に構成します。
primaryKeyBuilder1.addPrimaryKeyColumn("pk1", PrimaryKeyValue.fromString("pkvalue"));
primaryKeyBuilder1.addPrimaryKeyColumn("pk2", PrimaryKeyValue.fromLong(10001));
PrimaryKey primaryKey1 = primaryKeyBuilder1.build();
// 行の属性列を構成します。
RowPutChange rowPutChange = new RowPutChange(tableName, primaryKey1);
// 各属性列の列名、データ型、および列値を指定します。必要に応じて、さらに属性列を追加します。
rowPutChange.addColumn(new Column("col1", ColumnValue.fromString("colvalue")));
rowPutChange.addColumn(new Column("col2", ColumnValue.fromLong(10)));
PutRowRequest request1 = new PutRowRequest(rowPutChange);
// リクエストにローカル トランザクション ID を渡します。
request1.setTransactionId(txnId);
client.putRow(request1);
// ローカル トランザクションをコミットまたは中止します。
// ローカル トランザクションをコミットして、ローカル トランザクション内のすべてのデータ変更を有効にします。
CommitTransactionRequest commitRequest = new CommitTransactionRequest(txnId);
client.commitTransaction(commitRequest);
// ローカル トランザクションを中止して、ローカル トランザクション内のすべてのデータ変更を無効にします。
//AbortTransactionRequest abortRequest = new AbortTransactionRequest(txnId);
//client.abortTransaction(abortRequest);
}
ローカル トランザクション機能を使用してデータ行を読み取る
次のサンプルコードは、テーブル内の指定されたパーティションキー値に基づいてローカル トランザクションを作成する方法と、ローカル トランザクションでデータ行を読み取る方法を示しています。
private static void transactionGetRow(SyncClient client) {
// データテーブルの名前を指定します。
String tableName="exampletabled";
// 指定したパーティションキー値に基づいてローカル トランザクションを作成します。
PrimaryKeyBuilder primaryKeyBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
// パーティションキーの列名、データ型、および列値を指定します。
primaryKeyBuilder.addPrimaryKeyColumn("pk1", PrimaryKeyValue.fromString("111"));
PrimaryKey primaryKey = primaryKeyBuilder.build();
// ローカル トランザクションを作成するためのリクエストを構築します。
StartLocalTransactionRequest request = new StartLocalTransactionRequest(tableName, primaryKey);
// ローカル トランザクションを作成するリクエストを開始し、ローカル トランザクション ID を取得します。
String txnId = client.startLocalTransaction(request).getTransactionID();
// ローカル トランザクションでデータ行を読み取ります。
// 行のプライマリキー情報を構成します。
PrimaryKeyBuilder primaryKeyBuilder1 = PrimaryKeyBuilder.createPrimaryKeyBuilder();
// プライマリキーの列名、データ型、および列値を指定します。テーブルのプライマリキーが複数のプライマリキー列で構成されている場合は、プライマリキー列に関する情報を順番に構成します。
primaryKeyBuilder1.addPrimaryKeyColumn("pk1", PrimaryKeyValue.fromString("111"));
primaryKeyBuilder1.addPrimaryKeyColumn("pk2", PrimaryKeyValue.fromLong(10001));
PrimaryKey primaryKey1 = primaryKeyBuilder1.build();
SingleRowQueryCriteria criteria = new SingleRowQueryCriteria(tableName, primaryKey1);
// 最新バージョンのデータを読み取ります。
criteria.setMaxVersions(1);
GetRowRequest request1 = new GetRowRequest(criteria);
// リクエストにローカル トランザクション ID を渡します。
request1.setTransactionId(txnId);
GetRowResponse getRowResponse = client.getRow(request1);
// ローカル トランザクションをコミットまたは中止します。読み取り操作の場合、ローカル トランザクションのコミットと中止は同じ効果があります。
// ローカル トランザクションをコミットして、ローカル トランザクション内のすべてのデータ変更を有効にします。
CommitTransactionRequest commitRequest = new CommitTransactionRequest(txnId);
client.commitTransaction(commitRequest);
// ローカル トランザクションを中止して、ローカル トランザクション内のすべてのデータ変更を無効にします。
//AbortTransactionRequest abortRequest = new AbortTransactionRequest(txnId);
//client.abortTransaction(abortRequest);
// データ行を取得して表示します。
Row row = getRowResponse.getRow();
System.out.println("データ行が読み取られ、次のように表示されます:");
System.out.println(row);
}
課金
StartLocalTransaction、CommitTransaction、および AbortTransaction 操作は、それぞれ 1 つの書き込みキャパシティユニット (CU) を消費します。
ローカル トランザクション内のデータに対する読み取りおよび書き込み操作は、データに対する一般的な読み取りおよび書き込み操作を実行する場合と同じ方法で課金されます。課金の詳細については、課金の概要を参照してください。
エラーコード
エラーコード | 説明 |
OTSRowOperationConflict | パーティションキー値は既に別のローカル トランザクションによって使用されています。 |
OTSSessionNotExist | 指定されたトランザクション ID に対応するトランザクションが存在しないか、トランザクションが無効であるか、タイムアウトしました。 |
OTSSessionBusy | トランザクションに対する最後のリクエストが完了していません。 |
OTSOutOfTransactionDataSizeLimit | トランザクション内のデータ量が上限を超えています。 |
OTSDataOutOfRange | データ操作が、トランザクションの作成に使用されたパーティションキー値で指定された範囲外です。 |