SAA-C03Chapter 93 of 189Objective 2.3

DynamoDB Transactions

This chapter covers DynamoDB Transactions, a feature that enables atomic, consistent, isolated, and durable (ACID) operations across one or more items in DynamoDB tables. For the SAA-C03 exam, DynamoDB Transactions are tested under Resilient Architectures (Objective 2.3) and appear in approximately 5-8% of questions, often as part of a larger scenario involving data consistency, financial transactions, or inventory management. Understanding the transaction API, capacity consumption, error handling, and idempotency is critical to selecting the right solution for multi-item operations. This chapter provides a deep dive into the mechanics, configuration, and exam-specific nuances.

25 min read
Intermediate
Updated May 31, 2026

Bank Vault Transfer with Dual Control

Imagine two bank vaults, Vault A and Vault B, in separate branches. A customer wants to transfer $1,000 from Vault A to Vault B. The bank uses a dual-control procedure: two managers, Alice and Bob, must both approve. The process: Alice prepares a transfer slip for $1,000 debit from Vault A and $1,000 credit to Vault B. She locks the slip in a secure capsule and sends it to Bob. Bob receives the capsule, verifies the amounts, and unlocks it. He then checks that Vault A has sufficient funds (it does), and temporarily marks $1,000 as 'pending debit' in Vault A's ledger. He also marks a 'pending credit' of $1,000 in Vault B's ledger. Now both vaults have a temporary hold. Bob then commits: he finalizes the debit from Vault A and the credit to Vault B simultaneously. If at any point before commit a problem occurs—say Vault A's funds are insufficient or Bob's pen breaks—Bob can abort: the pending marks are removed, and both vaults return to their original state. This ensures that either both vaults are updated (the transfer happens) or neither is (the money stays put). The dual-control and two-phase locking (pending marks then commit) mirror DynamoDB Transactions' 'Prepare → Commit' mechanism, ensuring atomicity and isolation across multiple items.

How It Actually Works

What are DynamoDB Transactions?

DynamoDB Transactions extend DynamoDB's single-item ACID guarantees to multiple items across one or more tables. They provide full ACID compliance: Atomicity (all operations succeed or fail together), Consistency (data is consistent before and after the transaction), Isolation (intermediate states are invisible), and Durability (once committed, changes persist). Transactions are essential for use cases like financial transfers, order processing, and inventory management where multiple items must be updated in sync.

How Transactions Work Internally

DynamoDB uses a two-phase commit protocol: Prepare and Commit. When you call TransactWriteItems or TransactGetItems, the following happens:

1.

Client Request: The client sends a transaction request containing a list of operations (Put, Update, Delete, ConditionCheck for writes; Get for reads).

2.

Server-Side Prepare Phase: DynamoDB identifies all partitions involved. It sends a 'prepare' message to each partition, which locks the items (if writing) or reads the items (if reading) and buffers the changes. Locks are applied to prevent concurrent modifications. The prepare phase checks condition expressions and capacity. If any condition fails or capacity is insufficient, the transaction is aborted immediately.

3.

Server-Side Commit Phase: If all prepares succeed, DynamoDB sends a 'commit' message to all partitions. Each partition finalizes the changes and releases locks. The transaction is now durable.

4.

Client Response: The client receives a success response with consumed capacity details.

For reads (TransactGetItems), there is no lock; the items are read consistently across partitions, and the read is isolated from concurrent writes.

Transaction APIs

TransactWriteItems: A synchronous write operation that groups up to 25 actions (Put, Update, Delete, ConditionCheck) across up to 100 unique items or up to 4 MB of data. It can span multiple tables.

TransactGetItems: A synchronous read operation that groups up to 25 Get actions across up to 100 items or up to 4 MB. It provides strongly consistent reads by default.

Capacity Consumption

Transactions consume twice the write capacity units (WCUs) of a standard write. For a standard PutItem (1 KB item), 1 WCU is consumed. For the same item in a transaction, 2 WCUs are consumed (one for prepare, one for commit). Similarly, transactional reads consume twice the read capacity units (RCUs) of a standard strongly consistent read: 2 RCUs per 4 KB item (since a strongly consistent read normally costs 1 RCU per 4 KB, transactional read costs 2 RCUs). However, if the table uses on-demand capacity, there is no explicit capacity limit—but the cost per request is higher.

Idempotency Token

To prevent duplicate transactions due to retries, you can provide an idempotency token (ClientRequestToken) in the request. DynamoDB stores the token for 10 minutes after a successful transaction. If the same token is used again within 10 minutes, DynamoDB returns the previous response without re-executing the transaction. This is critical for retry logic in fault-tolerant applications.

Error Handling and Cancel Reasons

If a transaction fails, DynamoDB returns a TransactionCanceledException with a list of CancellationReasons for each action. Common reasons:

ConditionalCheckFailed: A condition expression evaluated to false.

ItemCollectionSizeLimitExceeded: The item collection (LSI/GSI) size limit exceeded.

TransactionConflict: A concurrent transaction or operation conflicted with the transaction.

ProvisionedThroughputExceeded: The table's provisioned capacity was exceeded.

ThrottlingError: General throttling.

ValidationError: Invalid request parameters.

Isolation Level

DynamoDB Transactions provide serializable isolation for writes and read-committed for reads. Serializability means the result of concurrent transactions is equivalent to some serial execution. In practice, this prevents dirty reads, non-repeatable reads, and phantom reads for write transactions. For TransactGetItems, the isolation is read-committed, meaning it reads only committed data, but it does not prevent other transactions from modifying the data after the read.

Constraints and Limits

Maximum number of actions in a single transaction: 25.

Maximum total data size: 4 MB (including item sizes and condition expressions).

Maximum number of unique items: 100.

Transaction duration: DynamoDB does not have a hard timeout but will abort if any partition does not respond within a short interval (typically seconds).

Transactions cannot span across tables in different AWS accounts or regions.

Transactions are not supported on global tables in the same way; they work but with additional latency due to replication.

Interaction with DynamoDB Streams

When a transaction writes to a table with DynamoDB Streams enabled, each individual item modification generates a stream record. The stream records appear after the transaction commits. However, the stream does not indicate that the modification was part of a transaction; you must infer it from the application logic. This is important for downstream processing like Lambda triggers.

Best Practices

Use transactions only when you need ACID across multiple items. For single-item operations, standard reads/writes are cheaper and faster.

Keep transactions small (few items, small sizes) to reduce latency and contention.

Use idempotency tokens for retry logic.

Design your partition key to avoid hot partitions; transactions that span many partitions increase latency.

Monitor TransactionConflict metrics in CloudWatch to detect contention.

Code Example (Python Boto3)

import boto3
from botocore.exceptions import ClientError

dynamodb = boto3.client('dynamodb')

try:
    response = dynamodb.transact_write_items(
        TransactItems=[
            {
                'Update': {
                    'TableName': 'Accounts',
                    'Key': {'AccountId': {'S': 'A123'}},
                    'UpdateExpression': 'SET balance = balance - :amt',
                    'ConditionExpression': 'balance >= :amt',
                    'ExpressionAttributeValues': {':amt': {'N': '100'}}
                }
            },
            {
                'Update': {
                    'TableName': 'Accounts',
                    'Key': {'AccountId': {'S': 'B456'}},
                    'UpdateExpression': 'SET balance = balance + :amt',
                    'ExpressionAttributeValues': {':amt': {'N': '100'}}
                }
            }
        ],
        ClientRequestToken='unique-token-123'
    )
    print("Transaction successful")
except ClientError as e:
    if e.response['Error']['Code'] == 'TransactionCanceledException':
        for cancel in e.response['CancellationReasons']:
            print(f"Action {cancel['Item']} failed: {cancel['Code']}")
    else:
        raise

Walk-Through

1

Client constructs transaction request

The application builds a list of up to 25 actions (Put, Update, Delete, ConditionCheck for writes; Get for reads). Each action specifies the table, key, and optional condition expression. The request can include an idempotency token (ClientRequestToken) and a ReturnConsumedCapacity parameter. The total request size must not exceed 4 MB. The client then calls either transact_write_items or transact_get_items via the DynamoDB API.

2

DynamoDB receives and validates request

DynamoDB validates the request syntax, checks that all referenced tables exist, and verifies that the total number of actions and items are within limits. It also checks the idempotency token cache: if the token was used successfully in the last 10 minutes, it returns the cached response without proceeding. Otherwise, the request moves to the prepare phase.

3

Prepare phase: lock and buffer

DynamoDB sends prepare messages to all partitions hosting the items. For writes, it acquires locks on the items (preventing concurrent modifications) and buffers the intended changes. For reads, it reads the current committed value. During this phase, condition expressions are evaluated. If any condition fails, or if any partition reports insufficient capacity or a conflict, the transaction is aborted. Locks are released immediately on abort.

4

Commit phase: finalize changes

If all prepare phases succeed, DynamoDB sends commit messages to all partitions. Each partition applies the buffered changes to the storage engine, releases locks, and makes the changes durable. The commit is atomic: either all partitions commit or none do. If a partition fails during commit, DynamoDB automatically rolls back the entire transaction.

5

Client receives response and handles errors

DynamoDB returns a success response with consumed capacity details (if requested). If the transaction failed, it returns a TransactionCanceledException with a list of CancellationReasons. The application should inspect the reasons and implement retry logic with idempotency tokens to handle transient failures like conflicts or throttling.

What This Looks Like on the Job

Scenario 1: Financial Transfer Service

A fintech company processes peer-to-peer payments. They use DynamoDB Transactions to atomically debit the sender's account and credit the recipient's account. Each account is a separate item in the same table, keyed by account ID. The transaction includes a ConditionExpression on the sender's item to ensure sufficient balance. The service uses an idempotency token derived from the payment ID to safely retry on network timeouts. In production, they handle thousands of transactions per second. Scaling considerations: they use on-demand capacity to avoid throttling during peak hours. They monitor the TransactionConflict metric; if it spikes, they reduce the number of items per transaction or optimize partition key design to avoid hot keys. A common misconfiguration is not using idempotency tokens, leading to duplicate payments when retries occur. They also ensure that the transaction does not exceed 4 MB; if a user has many pending transactions, they batch them into separate transactions.

Scenario 2: E-Commerce Order Processing

An e-commerce platform uses DynamoDB to manage inventory and orders. When a customer places an order, a transaction decrements the inventory count for each item in the order and creates an order record. The inventory items are in one table, and the order record is in another. The transaction includes a ConditionCheck on each inventory item to ensure stock is available. If any item is out of stock, the entire transaction fails, and the order is not created. This avoids partial orders. They use strongly consistent reads via TransactGetItems to verify cart prices before checkout. A common pitfall is exceeding the 25-action limit when an order contains many items; they must split into multiple transactions or use a different pattern (e.g., reserve inventory separately). They also discovered that transactions with many items (close to 25) have higher latency and are more prone to conflicts, so they keep transactions small.

Scenario 3: Multi-Table Data Synchronization

A gaming company maintains player profiles and game state in separate DynamoDB tables. When a player completes a quest, they earn experience points (XP) and unlock an achievement. The XP update goes to the player profile table, and the achievement record goes to the achievements table. They use a transaction to ensure both updates happen atomically. If the transaction fails due to a conflict (e.g., the player's profile is being updated by another transaction), they retry with exponential backoff. They use DynamoDB Streams on both tables to trigger downstream analytics. A challenge they faced: the transaction's idempotency token cache (10 minutes) is not sufficient for long-running retries; they implemented a custom idempotency layer using a separate table with TTL.

How SAA-C03 Actually Tests This

What SAA-C03 Tests

DynamoDB Transactions are tested under Objective 2.3 (Design resilient architectures) and also appear in Domain 3 (High-performing architectures). Exam questions typically present a scenario requiring ACID across multiple items and ask you to choose the best DynamoDB feature. Key objective codes: 2.3 (choose appropriate storage), 3.1 (choose compute and storage), 3.2 (choose database solutions).

Common Wrong Answers

1.

Using DynamoDB Streams + Lambda for multi-item updates: Candidates often assume that a Lambda function receiving stream events can coordinate updates. However, this does not provide atomicity; partial failures are possible. The exam expects you to recognize that transactions are the correct ACID solution.

2.

Using conditional writes with retries: Some think that multiple conditional writes (one per item) can achieve atomicity. But without a transaction, a failure after the first write leaves the system in an inconsistent state. The exam tests that only transactions provide atomicity across items.

3.

Using optimistic locking with version numbers: While versioning prevents overwrites, it does not guarantee that all updates succeed together. If one update fails, others may still be applied. The exam distinguishes between concurrency control and atomicity.

4.

Choosing standard reads/writes for simplicity: Candidates may overlook the need for ACID and choose cheaper operations, leading to data inconsistency. The exam expects you to identify when ACID is required (e.g., financial transfers).

Numbers and Terms to Memorize

Max 25 actions per transaction.

Max 100 unique items per transaction.

Max 4 MB total request size.

Idempotency token retention: 10 minutes.

Transactional writes consume 2 WCUs per 1 KB item (vs 1 WCU for standard).

Transactional reads consume 2 RCUs per 4 KB item (vs 1 RCU for strongly consistent).

TransactWriteItems and TransactGetItems are the API calls.

Cancellation reasons: ConditionalCheckFailed, TransactionConflict, ProvisionedThroughputExceeded.

Edge Cases and Exceptions

Transactions cannot span across tables in different AWS accounts or regions.

If a table has global secondary indexes (GSIs), the item collection size limit (10 GB per partition key) is enforced; transactions can fail with ItemCollectionSizeLimitExceeded.

Transactions on global tables are supported but may have higher latency due to cross-region replication. The exam may test that transactions are not a substitute for global table replication.

When using DynamoDB Streams with transactions, each individual item change appears in the stream; the stream does not group them as a single transaction.

How to Eliminate Wrong Answers

If the scenario requires all-or-nothing atomicity across multiple items, eliminate any option that does not use TransactWriteItems.

If the scenario requires a consistent snapshot read of multiple items, eliminate options that use eventual consistent reads or individual get requests.

Look for keywords: 'atomic', 'consistent', 'rollback', 'all-or-nothing'. These point to transactions.

If the scenario mentions high throughput and low latency, consider that transactions double capacity consumption; standard operations may be better if ACID is not needed.

If the scenario involves only one item, a transaction is overkill; use standard PutItem with conditional writes.

Key Takeaways

DynamoDB Transactions provide ACID across multiple items and tables using a two-phase commit protocol.

Use TransactWriteItems for atomic writes (up to 25 actions, 4 MB, 100 unique items).

Use TransactGetItems for strongly consistent multi-item reads.

Transactional writes consume 2 WCUs per 1 KB; transactional reads consume 2 RCUs per 4 KB.

Idempotency tokens (ClientRequestToken) prevent duplicate transactions for 10 minutes.

On failure, examine CancellationReasons to identify the cause (e.g., ConditionalCheckFailed, TransactionConflict).

Transactions are not supported across regions or accounts.

For single-item operations, standard writes are cheaper and faster.

Design partition keys to avoid hot partitions to reduce TransactionConflict errors.

DynamoDB Streams records individual item changes, not the transaction as a whole.

Easy to Mix Up

These come up on the exam all the time. Here's how to tell them apart.

DynamoDB Transactions (TransactWriteItems)

Provides atomicity across multiple items and tables.

Consumes 2 WCUs per 1 KB item.

Supports up to 25 actions per transaction.

Automatically rolls back on failure.

Isolation level: serializable for writes.

Standard Writes (PutItem/UpdateItem) with Conditional Expressions

Provides atomicity only at single-item level.

Consumes 1 WCU per 1 KB item.

No limit on number of writes (but each is separate).

No automatic rollback; partial updates possible.

Isolation: eventual consistency by default.

DynamoDB Transactions

Synchronous, immediate consistency.

No additional services needed.

Automatically handles conflicts and retries.

Lower latency for small operations.

Capacity consumption is doubled.

DynamoDB Streams + Lambda for Coordination

Asynchronous, eventual consistency.

Requires Lambda and Streams setup.

Must implement custom conflict resolution and rollback.

Higher latency due to stream processing.

Capacity consumption is per write/read (no doubling).

Watch Out for These

Mistake

DynamoDB Transactions are the same as SQL database transactions with full ACID across tables.

Correct

DynamoDB Transactions provide ACID across multiple items and tables, but they are limited to 25 actions and 4 MB. They are not as flexible as SQL transactions (e.g., no support for stored procedures, no long-running transactions). They also do not support rollback to savepoints; a failure cancels the entire transaction.

Mistake

Transactions consume the same read/write capacity as standard operations.

Correct

Transactional writes consume 2 WCUs per 1 KB item (double). Transactional reads consume 2 RCUs per 4 KB item (double a strongly consistent read). This is because of the two-phase commit overhead.

Mistake

You can use TransactGetItems to read items that are being modified by a concurrent TransactWriteItems without any isolation issues.

Correct

TransactGetItems provides read-committed isolation, meaning it reads only committed data. It will not see uncommitted changes. However, it does not prevent other transactions from modifying the data; it may get stale data if read before a concurrent write commits.

Mistake

Idempotency tokens guarantee exactly-once execution for 24 hours.

Correct

Idempotency tokens are stored for only 10 minutes after a successful transaction. After that, the same token will be treated as a new request and may cause duplicate execution. Applications must handle retries within this window or implement custom idempotency.

Mistake

Transactions can include up to 100 actions.

Correct

The limit is 25 actions per transaction, not 100. The 100 refers to the maximum number of unique items that can be touched by those 25 actions (e.g., if you update the same item multiple times, it counts once toward the 100-item limit).

Do You Actually Know This?

Reveal each answer, then mark whether you got it right. Score 60%+ to unlock the next chapter.

Frequently Asked Questions

What is the difference between TransactWriteItems and BatchWriteItem in DynamoDB?

BatchWriteItem writes multiple items in parallel but does not provide atomicity: some writes can succeed while others fail. TransactWriteItems ensures all writes succeed or none do. Also, BatchWriteItem can only put or delete items (not update or condition check), and it consumes standard capacity (1 WCU per 1 KB). TransactWriteItems consumes double capacity. Use BatchWriteItem for high-throughput batch writes where atomicity is not required; use TransactWriteItems when you need ACID.

Can I use DynamoDB Transactions with global tables?

Yes, DynamoDB Transactions are supported on global tables. However, because global tables replicate data across regions, transactions may have higher latency. The transaction is executed in the region where the request is made, and the changes are then replicated asynchronously to other regions. The transaction itself does not span regions; it only operates on items in the local region's replica. For cross-region ACID, you would need a different approach (e.g., application-level coordination).

How do I handle transaction conflicts in DynamoDB?

Transaction conflicts occur when two concurrent transactions try to modify the same item. DynamoDB returns a TransactionCanceledException with CancellationReason 'TransactionConflict'. To handle this, retry the transaction with exponential backoff and jitter. Use an idempotency token to avoid duplicate effects. Also, design your partition keys to distribute writes evenly to reduce contention. Consider using smaller transactions that touch fewer items.

What happens if a transaction exceeds the 4 MB limit?

DynamoDB will reject the request with a ValidationError. You must reduce the size of the transaction, either by reducing the number of items or the size of each item. For large payloads, consider storing larger data in S3 and storing only the S3 key in DynamoDB. Alternatively, split the transaction into multiple smaller transactions if atomicity across all items is not required.

Can I use transactions on tables with auto scaling or on-demand capacity?

Yes, transactions work with both provisioned and on-demand capacity. With on-demand, there is no explicit capacity limit, but you still pay per request. With provisioned capacity, ensure your table has enough WCUs and RCUs to handle the doubled consumption. If you exceed provisioned capacity, the transaction will be throttled and return a ProvisionedThroughputExceeded error.

How do I monitor DynamoDB Transactions?

Use Amazon CloudWatch metrics: TransactionConflict, ConditionalCheckFailedRequests, ThrottledRequests, and ConsumedReadCapacityUnits/ConsumedWriteCapacityUnits. Enable CloudTrail to log API calls. You can also use DynamoDB Streams to capture item-level changes post-commit. For debugging, return CancellationReasons in your error handling.

What is the isolation level of TransactGetItems?

TransactGetItems provides read-committed isolation. It reads only data that has been committed. However, it does not prevent other transactions from writing to the same items after the read, so subsequent reads may see different data. For serializable reads, you would need to use TransactWriteItems with a ConditionCheck to lock the items.

Terms Worth Knowing

Ready to put this to the test?

You've just covered DynamoDB Transactions — now see how well it sticks with free SAA-C03 practice questions. Full explanations included, no account needed.

Done with this chapter?