本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。
以 Amazon DynamoDB Transactions 十分實用的情況作為範例,請考慮此線上市場的 Java 應用程式範例。
應用程式在其後端有三個 DynamoDB 資料表:
Customers
:此資料表儲存有關市場客戶的詳細資訊。其主索引鍵為CustomerId
唯一識別符。ProductCatalog
:此資料表儲存的詳細資訊包括關於市場上銷售之產品的價格和供貨情況。其主索引鍵為ProductId
唯一識別符。Orders
:此資料表儲存有關市場訂單的詳細資訊。其主索引鍵為OrderId
唯一識別符。
下訂單
下列程式碼片段說明如何使用 DynamoDB 交易來協調建立和處理訂單所需的多個步驟。使用單一 all-or-nothing操作可確保如果交易的任何部分失敗,交易中不會執行任何動作,也不會進行任何變更。
在此範例中,您可以為 customerId
為 09e8e9c8-ec48
的客戶設定訂單。然後,您可以使用下列簡單的訂單處理工作流程,將其當作單一交易執行:
判斷客戶 ID 有效。
確定產品為
IN_STOCK
,並將產品狀態更新為SOLD
。請確定訂單不存在,並建立訂單。
驗證客戶
首先,請定義一個動作,以便驗證客戶資料表中是否存在 customerId
等於 09e8e9c8-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
的動作。如果項目的產品狀態屬性不等於 IN_STOCK
,則設定 ReturnValuesOnConditionCheckFailure
參數會傳回項目。
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 + ")");
執行交易
下列範例說明如何執行先前定義為單一 all-or-nothing操作的動作。
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);
// Run 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);
// Run 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());
}