Exemple de transactions DynamoDB - Amazon DynamoDB

Les traductions sont fournies par des outils de traduction automatique. En cas de conflit entre le contenu d'une traduction et celui de la version originale en anglais, la version anglaise prévaudra.

Exemple de transactions DynamoDB

A titre d'exemple de situation dans laquelle des transactions Amazon DynamoDB peuvent être utiles, considérez cette application Java pour une place de marché en ligne.

L'application dispose de trois tables DynamoDB dans le backend :

  • Customers – Cette table stocke des détails sur les clients de la place de marché. Sa clé primaire est un identifiant unique CustomerId.

  • ProductCatalog – Ce tableau stocke des détails tels que le prix et la disponibilité des produits en vente sur la place de marché. Sa clé primaire est un identifiant unique ProductId.

  • Orders – Cette table stocke des détails sur les commandes en provenance de la place de marché. Sa clé primaire est un identifiant unique OrderId.

Passation d'une commande

Les extraits de code suivants montrent comment utiliser des transactions DynamoDB pour coordonner les différentes étapes de la création et du traitement d'une commande. L'utilisation d'une seule all-or-nothing opération garantit qu'en cas d'échec d'une partie de la transaction, aucune action de la transaction n'est exécutée et aucune modification n'est apportée.

Dans cet exemple, vous configurez une commande à partir d'un client dont le customerId est 09e8e9c8-ec48. Vous l'exécutez ensuite en tant que transaction unique à l'aide du simple flux de traitement de commandes suivant :

  1. Déterminez si l'ID client est valide.

  2. Assurez-vous que l'état du produit est IN_STOCK et mettez à jour son état en SOLD.

  3. Assurez-vous que la commande n'existe pas déjà, puis créez la commande.

Valider le client

Commencez par définir une action pour vérifier qu'un client avec customerId égal à 09e8e9c8-ec48 existe dans la table client.

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

Mettre à jour l'état du produit

Ensuite, définissez une action pour mettre à jour l'état du produit sur SOLD si la condition que l'état du produit soit actuellement défini sur IN_STOCK est true. La définition du paramètre ReturnValuesOnConditionCheckFailure a pour effet de renvoyer l'article si l'attribut d'état de produit de celui-ci n'est pas 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);

Créer la commande

Enfin, créez la commande pour autant qu'il n'existe pas de commande avec cet 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 + ")");

Exécuter la transaction

L'exemple suivant montre comment exécuter les actions définies précédemment en une seule all-or-nothing opération.

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

Lecture des détails de la commande

L'exemple suivant montre comment lire la commande terminée de manière transactionnelle dans les tables Orders et 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()); }