DynamoDB Transactions 예 - Amazon DynamoDB

DynamoDB Transactions 예

Amazon DynamoDB Transactions가 유용할 수 있는 상황의 예로 온라인 마켓플레이스용 이 샘플 Java 애플리케이션을 고려하세요.

이 애플리케이션의 백엔드에는 다음 세 개의 DynamoDB 테이블이 있습니다.

  • Customers - 이 테이블은 마켓플레이스 고객에 대한 세부 정보를 저장합니다. 기본 키는 CustomerId 고유 식별자입니다.

  • ProductCatalog - 이 테이블은 마켓플레이스에서 판매할 제품에 대한 가격, 가용성 등의 세부 정보를 저장합니다. 기본 키는 ProductId 고유 식별자입니다.

  • Orders - 이 테이블은 마켓플레이스에서 수행된 주문에 대한 세부 정보를 저장합니다. 기본 키는 OrderId 고유 식별자입니다.

주문하기

다음 코드 조각은 DynamoDB 트랜잭션을 사용하여 주문을 생성 및 처리하는 데 필요한 여러 단계를 조정하는 방법을 보여 줍니다. 하나의 양자택일 방식 작업을 사용하면 트랜잭션의 일부라도 실패할 경우 트랜잭션에서 아무 작업도 실행되지 않고 아무 내용도 변경되지 않습니다.

이 예제에서는 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 + ")");

트랜잭션 실행

다음 예제는 앞에서 정의한 작업을 하나의 양자택일 방식 작업으로 실행하는 방법을 보여 줍니다.

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

주문 세부 정보 읽기

다음 예제는 OrdersProductCatalog 테이블에서 완료된 주문 트랜잭션을 읽는 방법을 보여줍니다.

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