Amazon DynamoDB
開発者ガイド (API バージョン 2012-08-10)

DynamoDB トランザクションの例

Amazon DynamoDB トランザクションが役立つ情報の例として、オンラインマーケットプレイスのこのサンプル Java アプリケーションについて考えます。

このアプリケーションでは、バックエンドに 3 つの DynamoDB テーブルがあります。

  • Customers — このテーブルには、マーケットプレイス顧客に関する詳細が保存されます。そのプライマリキーは、一意識別子の CustomerId です。

  • ProductCatalog — このテーブルには、マーケットプレイスで販売される製品の価格や在庫状況などの詳細が保存されます。そのプライマリキーは、一意識別子の ProductId です。

  • Orders — このテーブルには、マーケットプレイスからの注文に関する詳細が保存されます。そのプライマリキーは、一意識別子の OrderId です。

注文の実行

以下のコードスニペットは、DynamoDB トランザクションを使用して、注文の作成と処理に必要な複数のステップを調整する方法を示しています。1 つのオールオアナッシングオペレーションを使用すると、トランザクションのいずれかの部分が失敗した場合、トランザクションのどのアクションも実行されないため、料金が発生しません。

この例では、customerId09e8e9c8-ec48 である顧客の注文を設定します。その後、次のシンプルな注文処理ワークフローを使用して、設定した注文を単一のトランザクションとして実行します。

  1. 顧客 ID が有効であることを確認します。

  2. 製品が IN_STOCK であることを確認し、製品のステータスを SOLD に更新します。

  3. 注文がまだ存在しないことを確認し、注文を作成します。

顧客の確認

まず、customerId09e8e9c8-ec48 に等しい顧客が顧客テーブルに存在することを確認するテーブルを定義します。

final String CUSTOMER_TABLE_NAME = "Customers"; final String CUSTOMER_PARTITION_KEY = "CustomerId"; final String customerId = "09e8e9c8-ec48"; final HashMap<String, AttributeValue> customerItemKey = new HashMap<>(); customerItemKey.put(CUSTOMER_PARTITION_KEY, new AttributeValue(customerId)); ConditionCheck checkCustomerValid = new ConditionCheck() .withTableName(CUSTOMER_TABLE_NAME) .withKey(customerItemKey) .withConditionExpression("attribute_exists(" + CUSTOMER_PARTITION_KEY + ")");

製品ステータスの更新

次に、製品のステータスが現在 IN_STOCK に設定されている条件が true の場合、製品のステータスを SOLD に更新するアクションを定義します。ReturnValuesOnConditionCheckFailure パラメータを設定すると、項目の製品ステータス属性が IN_STOCK と等しくなかった場合に項目が返されます。

final String PRODUCT_TABLE_NAME = "ProductCatalog"; final String PRODUCT_PARTITION_KEY = "ProductId"; HashMap<String, AttributeValue> productItemKey = new HashMap<>(); productItemKey.put(PRODUCT_PARTITION_KEY, new AttributeValue(productKey)); Map<String, AttributeValue> expressionAttributeValues = new HashMap<>(); expressionAttributeValues.put(":new_status", new AttributeValue("SOLD")); expressionAttributeValues.put(":expected_status", new AttributeValue("IN_STOCK")); Update markItemSold = new Update() .withTableName(PRODUCT_TABLE_NAME) .withKey(productItemKey) .withUpdateExpression("SET ProductStatus = :new_status") .withExpressionAttributeValues(expressionAttributeValues) .withConditionExpression("ProductStatus = :expected_status") .withReturnValuesOnConditionCheckFailure(ReturnValuesOnConditionCheckFailure.ALL_OLD);

注文の作成

最後に、その OrderId の注文がまだ存在しない限り、注文を作成します。

final String ORDER_PARTITION_KEY = "OrderId"; final String ORDER_TABLE_NAME = "Orders"; HashMap<String, AttributeValue> orderItem = new HashMap<>(); orderItem.put(ORDER_PARTITION_KEY, new AttributeValue(orderId)); orderItem.put(PRODUCT_PARTITION_KEY, new AttributeValue(productKey)); orderItem.put(CUSTOMER_PARTITION_KEY, new AttributeValue(customerId)); orderItem.put("OrderStatus", new AttributeValue("CONFIRMED")); orderItem.put("OrderTotal", new AttributeValue("100")); Put createOrder = new Put() .withTableName(ORDER_TABLE_NAME) .withItem(orderItem) .withReturnValuesOnConditionCheckFailure(ReturnValuesOnConditionCheckFailure.ALL_OLD) .withConditionExpression("attribute_not_exists(" + ORDER_PARTITION_KEY + ")");

トランザクションの実行

以下の例は、以前に定義されたアクションを 1 つのオールオアナッシングオペレーションとして実行する方法を示しています。

Collection<TransactWriteItem> actions = Arrays.asList( new TransactWriteItem().withConditionCheck(checkCustomerValid), new TransactWriteItem().withUpdate(markItemSold), new TransactWriteItem().withPut(createOrder)); TransactWriteItemsRequest placeOrderTransaction = new TransactWriteItemsRequest() .withTransactItems(actions) .withReturnConsumedCapacity(ReturnConsumedCapacity.TOTAL); // Execute the transaction and process the result. try { client.transactWriteItems(placeOrderTransaction); System.out.println("Transaction Successful"); } catch (ResourceNotFoundException rnf) { System.err.println("One of the table involved in the transaction is not found" + rnf.getMessage()); } catch (InternalServerErrorException ise) { System.err.println("Internal Server Error" + ise.getMessage()); } catch (TransactionCanceledException tce) { System.out.println("Transaction Canceled " + tce.getMessage()); }

注文の詳細の読み取り

次の例では、Orders および ProductCatalog テーブル間で完了した注文をトランザクションとして読み取る方法を示します。

HashMap<String, AttributeValue> productItemKey = new HashMap<>(); productItemKey.put(PRODUCT_PARTITION_KEY, new AttributeValue(productKey)); HashMap<String, AttributeValue> orderKey = new HashMap<>(); orderKey.put(ORDER_PARTITION_KEY, new AttributeValue(orderId)); Get readProductSold = new Get() .withTableName(PRODUCT_TABLE_NAME) .withKey(productItemKey); Get readCreatedOrder = new Get() .withTableName(ORDER_TABLE_NAME) .withKey(orderKey); Collection<TransactGetItem> getActions = Arrays.asList( new TransactGetItem().withGet(readProductSold), new TransactGetItem().withGet(readCreatedOrder)); TransactGetItemsRequest readCompletedOrder = new TransactGetItemsRequest() .withTransactItems(getActions) .withReturnConsumedCapacity(ReturnConsumedCapacity.TOTAL); // Execute the transaction and process the result. try { TransactGetItemsResult result = client.transactGetItems(readCompletedOrder); System.out.println(result.getResponses()); } catch (ResourceNotFoundException rnf) { System.err.println("One of the table involved in the transaction is not found" + rnf.getMessage()); } catch (InternalServerErrorException ise) { System.err.println("Internal Server Error" + ise.getMessage()); } catch (TransactionCanceledException tce) { System.err.println("Transaction Canceled" + tce.getMessage()); }

その他の例