作为 Amazon DynamoDB Transactions 可能有用的情况示例,请考虑此适用于在线商城的 Java 应用程序示例。
该应用程序在后端有三个 DynamoDB 表:
Customers
— 此表存储有关商城买家的详细信息。它的主键是CustomerId
唯一标识符。ProductCatalog
— 此表存储有关商品在商城中销售的价格和供货情况等详细信息。它的主键是ProductId
唯一标识符。Orders
— 此表存储有关来自市场的订单的详细信息。它的主键是OrderId
唯一标识符。
下订单
以下代码片段说明了如何使用 DynamoDB 事务来协调创建和处理订单所需的多个步骤。使用单个全有或全无操作可确保如果事务的任何部分失败,事务中不会运行任何操作,也不会进行任何更改。
在此示例中,您设置来自 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
。设置 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 + ")");
运行事务
以下示例说明如何运行以前定义为单个全有或全无操作的操作。
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());
}