DynamoDB Transactions 예
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()); }