Tablestore SDK for Java では、書き込み操作または削除操作に条件を付与できます。Tablestore は、対象の行が条件を満たす場合にのみ操作を実行し、満たさない場合はエラーを返します。条件付き更新を使用することで、オプティミスティックロックを実装したり、読み取っていない同時変更を上書きしてしまう事態を防いだりできます。
前提条件
Tablestore SDK for Java をインストールし、クライアントを初期化します。
仕組み
条件付き更新では、書き込みまたは削除操作に条件を付加できます。Condition コンテナーには、行の存在条件 (rowExistenceExpectation)、列条件 (columnCondition)、またはその両方が含まれます。設定した Condition を RowPutChange、RowUpdateChange、または RowDeleteChange の setCondition() に渡します。条件が満たされない場合、サーバーはエラーを返し、行は変更されません。
関連するクラスは次のとおりです:
public class Condition {
private RowExistenceExpectation rowExistenceExpectation;
private ColumnCondition columnCondition;
}
public class SingleColumnValueCondition extends ColumnCondition
public class CompositeColumnValueCondition extends ColumnCondition
次の例では、condition_demo テーブルのプライマリキー row1 を持つ行を、行が存在する場合にのみ 更新します。それ以外の場合、サーバーはエラーを返します。
PrimaryKey primaryKey = PrimaryKeyBuilder.createPrimaryKeyBuilder()
.addPrimaryKeyColumn("id", PrimaryKeyValue.fromString("row1"))
.build();
RowUpdateChange rowUpdateChange = new RowUpdateChange("condition_demo", primaryKey);
rowUpdateChange.put("col1", ColumnValue.fromString("changed_val1"));
Condition condition = new Condition();
condition.setRowExistenceExpectation(RowExistenceExpectation.EXPECT_EXIST);
rowUpdateChange.setCondition(condition);
UpdateRowResponse response = client.updateRow(new UpdateRowRequest(rowUpdateChange));
System.out.println("RequestId: " + response.getRequestId());
System.out.println("Write CU: " + response.getConsumedCapacity().getCapacityUnit().getWriteCapacityUnit());
Condition、rowExistenceExpectation、および columnCondition のすべてのフィールドについては、パラメータをご参照ください。
パラメータ
Condition
Condition は条件のコンテナです。行存在条件フィールドと列条件フィールドが含まれます。少なくとも 1 つのフィールドを設定する必要があります。
|
名前 |
タイプ |
説明 |
|
rowExistenceExpectation (オプション) |
RowExistenceExpectation |
行存在条件。有効な値は次のとおりです:
|
|
columnCondition (オプション) |
ColumnCondition |
列条件。サブクラスとして、単一列チェック用の |
SingleColumnValueCondition
new SingleColumnValueCondition(columnName, operator, columnValue) で構築します。
|
名前 |
タイプ |
説明 |
|
columnName (必須) |
String |
チェック対象の属性列の名前。 |
|
operator (必須) |
CompareOperator |
比較演算子。有効な値は次のとおりです:
|
|
columnValue (必須) |
ColumnValue |
比較対象の値。 |
|
passIfMissing (オプション) |
boolean |
対象の属性列が存在しない場合に、行が条件を満たしているとみなすかどうか。デフォルト値は 列が存在しない場合に条件を満たしていないとみなすには、 |
|
latestVersionsOnly (オプション) |
boolean |
最新のデータバージョンのみをチェックするかどうか。デフォルト値は いずれかのバージョンが条件を満たす場合に一致させるには、 |
CompositeColumnValueCondition
new CompositeColumnValueCondition(logicOperator) で構築します。addCondition() でサブ条件を追加します。最大 32 個のサブ条件を追加できます。
|
名前 |
タイプ |
説明 |
|
logicOperator (必須) |
LogicOperator |
論理演算子。有効な値は次のとおりです:
|
|
conditions (必須) |
List<ColumnCondition> |
論理演算のサブ条件。 |
例
単一列値条件
SingleColumnValueCondition を使用して、単一の属性列の値をチェックします。次の例では、プライマリキー row1 を持つ行の col2 を、col1 == "changed_val1" の場合にのみ更新します。
PrimaryKey primaryKey = PrimaryKeyBuilder.createPrimaryKeyBuilder()
.addPrimaryKeyColumn("id", PrimaryKeyValue.fromString("row1"))
.build();
RowUpdateChange rowUpdateChange = new RowUpdateChange("condition_demo", primaryKey);
rowUpdateChange.put("col2", ColumnValue.fromString("new_val2"));
Condition condition = new Condition();
SingleColumnValueCondition singleCondition = new SingleColumnValueCondition(
"col1",
SingleColumnValueCondition.CompareOperator.EQUAL,
ColumnValue.fromString("changed_val1"));
condition.setColumnCondition(singleCondition);
rowUpdateChange.setCondition(condition);
client.updateRow(new UpdateRowRequest(rowUpdateChange));
複合列値条件
CompositeColumnValueCondition を使用して、論理演算子で複数の条件を組み合わせます。複合条件はネストすることも可能です。次の例では、(col1 == "changed_val1" AND col2 == "new_val2") OR (col3 == "val3") という条件を構築します。
PrimaryKey primaryKey = PrimaryKeyBuilder.createPrimaryKeyBuilder()
.addPrimaryKeyColumn("id", PrimaryKeyValue.fromString("row1"))
.build();
RowUpdateChange rowUpdateChange = new RowUpdateChange("condition_demo", primaryKey);
rowUpdateChange.put("col1", ColumnValue.fromString("final_val1"));
// サブ条件: col1 == "changed_val1" AND col2 == "new_val2"
CompositeColumnValueCondition andCondition = new CompositeColumnValueCondition(
CompositeColumnValueCondition.LogicOperator.AND);
andCondition.addCondition(new SingleColumnValueCondition(
"col1",
SingleColumnValueCondition.CompareOperator.EQUAL,
ColumnValue.fromString("changed_val1")));
andCondition.addCondition(new SingleColumnValueCondition(
"col2",
SingleColumnValueCondition.CompareOperator.EQUAL,
ColumnValue.fromString("new_val2")));
// トップレベルのOR: (col1 AND col2) OR (col3)
CompositeColumnValueCondition orCondition = new CompositeColumnValueCondition(
CompositeColumnValueCondition.LogicOperator.OR);
orCondition.addCondition(andCondition);
orCondition.addCondition(new SingleColumnValueCondition(
"col3",
SingleColumnValueCondition.CompareOperator.EQUAL,
ColumnValue.fromString("val3")));
Condition condition = new Condition();
condition.setColumnCondition(orCondition);
rowUpdateChange.setCondition(condition);
client.updateRow(new UpdateRowRequest(rowUpdateChange));
コンペアアンドスワップを使用したオプティミスティックロック
条件付き更新を使用してコンペアアンドスワップを実装します。まず現在の値を読み取り、次にその値を更新条件として渡します。更新は、列が読み取った値を保持している場合にのみ成功します。読み取りと書き込みの間に別のプロセスが列を変更した場合、更新は失敗します。これにより、そのプロセスの書き込みを上書きしてしまう事態を防ぐことができます。
PrimaryKey primaryKey = PrimaryKeyBuilder.createPrimaryKeyBuilder()
.addPrimaryKeyColumn("id", PrimaryKeyValue.fromString("row1"))
.build();
// 1. 現在の値を読み取ります。
SingleRowQueryCriteria queryCriteria = new SingleRowQueryCriteria("condition_demo", primaryKey);
queryCriteria.setMaxVersions(1);
GetRowResponse getResponse = client.getRow(new GetRowRequest(queryCriteria));
String oldValue = getResponse.getRow().getLatestColumn("col1").getValue().asString();
// 2. 読み取った値に基づいて条件付き更新を実行します (col1 が oldValue と等しい場合にのみ更新)。
RowUpdateChange rowUpdateChange = new RowUpdateChange("condition_demo", primaryKey);
rowUpdateChange.put("col1", ColumnValue.fromString("cas_updated"));
Condition condition = new Condition(RowExistenceExpectation.EXPECT_EXIST);
SingleColumnValueCondition casCondition = new SingleColumnValueCondition(
"col1",
SingleColumnValueCondition.CompareOperator.EQUAL,
ColumnValue.fromString(oldValue));
casCondition.setPassIfMissing(false);
casCondition.setLatestVersionsOnly(true);
condition.setColumnCondition(casCondition);
rowUpdateChange.setCondition(condition);
client.updateRow(new UpdateRowRequest(rowUpdateChange));