Skip to content
Quest 13Advanced20 min

Trading with Rival (Transactions)

You want to trade your Scyther for your rival's Onix. This involves two database updates: 1) Set Scyther's owner to your rival, 2) Set Onix's owner to you. If step 1 succeeds but step 2 fails, you've lost your Pokémon! DynamoDB Transactions prevent this.
Start the lesson

What you'll learn

  • TransactWriteItems supports up to 100 distinct items totaling 4 MB, within one AWS account and Region. No two actions may target the same item.
  • Either all operations succeed, or they all fail together.
  • Transactions use two underlying writes per item. Reuse a ClientRequestToken for identical application retries within its 10-minute idempotency window.
  • Condition each write on the expected owner to prevent a stale trade from overwriting newer state.

Section 01

Trading Pokémon Safely (ACID)

By wrapping our updates in a TransactWriteItems call, we ensure that the trade is atomic. If the Onix condition fails (maybe it was already traded!), DynamoDB cancels the whole transaction with a TransactionCanceledException (its CancellationReasons say which action failed), so Scyther never changes hands either.

TransactWriteItemsJavaScript
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
import { DynamoDBDocumentClient, TransactWriteCommand } from "@aws-sdk/lib-dynamodb";

const client = new DynamoDBClient({ region: "ap-south-1" });
const docClient = DynamoDBDocumentClient.from(client);

await docClient.send(new TransactWriteCommand({
  TransactItems: [
    {
      Update: {
        TableName: "TrainerPokemon",
        Key: { Name: "Scyther" },
        UpdateExpression: "SET #own = :rival",
        ExpressionAttributeNames: { "#own": "Owner" },
        ExpressionAttributeValues: { ":rival": "Gary", ":expected": "Ash" },
        ConditionExpression: "#own = :expected"
      }
    },
    {
      Update: {
        TableName: "TrainerPokemon",
        Key: { Name: "Onix" },
        UpdateExpression: "SET #own = :you",
        ExpressionAttributeNames: { "#own": "Owner" },
        ExpressionAttributeValues: { ":you": "Ash", ":expected": "Gary" },
        ConditionExpression: "#own = :expected"
      }
    }
  ]
}));
Your appAWS SDK v3DynamoDBtableP0P1P2P3CONSUMED0

Ready · 6 steps · Mote

This animation plays when you scroll to it. Press Play to start it now.

All steps as text
  1. Your app sends UpdateItem to the JohtoPokemon table with Name = "Scyther". Two separate writes, no transaction.
  2. DynamoDB hashes "Scyther" to 4eaf361b, which routes the request to partition P3.
  3. P3 updates Scyther (Owner Ash → Gary).
  4. Your app sends UpdateItem to the JohtoPokemon table with Name = "Onix".
  5. DynamoDB hashes "Onix" to 3c63cf55, which routes the request to partition P1.
  6. DynamoDB responds with RequestTimeout: the second write never landed: Gary has both Pokémon and Ash has neither.

Practice

Your turn

Trading Scyther for Onix is two writes that must both succeed or both fail. Complete the TransactWriteCommand by adding the second Update that hands Onix to you.
Add the second Update, and give both updates a condition that checks the expected current owner before swapping them.
Tab inserts two spaces. Press Escape, then Tab, to leave the editor. Control or Command plus Enter runs the code.
Simulated — no AWS calls

Check

Check your understanding

Quick Quiz · one question, as many tries as you need.

What DynamoDB operation guarantees that multiple item updates either all succeed or all fail?

Choose one answer.