

# Exemplo de transações do DynamoDB
<a name="transaction-example"></a>

Como exemplo de uma situação em que as Amazon DynamoDB Transactions podem ser úteis, considere este exemplo de aplicação Java para um marketplace online.

A aplicação tem três tabelas do DynamoDB no backend:
+ `Customers`: esta tabela armazena detalhes sobre os clientes do marketplace. Sua chave primária é um identificador exclusivo `CustomerId`.
+ `ProductCatalog`: esta tabela armazena detalhes como preço e disponibilidade sobre os produtos para venda no mercado. Sua chave primária é um identificador exclusivo `ProductId`.
+ `Orders`: esta tabela armazena detalhes sobre os pedidos do marketplace. Sua chave primária é um identificador exclusivo `OrderId`.

## Fazer um pedido
<a name="transaction-example-write-order"></a>

Os trechos de código a seguir ilustram como usar transações do DynamoDB para coordenar as várias etapas necessárias para criar e processar um pedido. O uso de uma única operação de tudo ou nada garante que, se qualquer parte da transação falhar, nenhuma ação na transação será executada e nenhuma alteração será feita.

Neste exemplo, você configura um pedido de um cliente cujo `customerId` é `09e8e9c8-ec48`. Em seguida, execute-o como uma única transação usando o seguinte fluxo de trabalho simples de processamento de pedidos:

1. Determine se o ID do cliente é válido.

1. Verifique se o produto é `IN_STOCK` e atualize o status do produto para `SOLD`.

1. Certifique-se de que o pedido ainda não exista e crie-o.

### Validar o cliente
<a name="transaction-example-order-part-a"></a>

Primeiro, defina uma ação para verificar se um cliente com `customerId` igual a `09e8e9c8-ec48` existe na tabela de clientes.

```
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 + ")");
```

### Atualizar o status do produto
<a name="transaction-example-order-part-b"></a>

Em seguida, defina uma ação para atualizar o status do produto para `SOLD` se a condição do status atual do produto `IN_STOCK` for `true`. Configurar a opção `ReturnValuesOnConditionCheckFailure` retornará o item se o atributo de status do produto do item não for igual a `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);
```

### Criar o pedido
<a name="transaction-example-order-part-c"></a>

Por último, crie o pedido, desde que um pedido com esse `OrderId` ainda não exista.

```
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 + ")");
```

### Executar a transação
<a name="transaction-example-order-part-d"></a>

O exemplo a seguir ilustra como executar as ações definidas anteriormente como uma única operação tudo ou nada.

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

## Ler os detalhes do pedido
<a name="transaction-example-read-order"></a>

O exemplo a seguir mostra como ler a ordem concluída transacionalmente entre as tabelas `Orders` e `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());
}
```