This chapter covers DynamoDB Transactions and Conditional Writes, two critical mechanisms for ensuring data consistency in DynamoDB. For the DVA-C02 exam, these topics appear in roughly 10-15% of questions, often in scenarios involving financial applications, inventory management, or any multi-item update that must be atomic. Understanding the differences between conditional writes (single-item, optimistic locking) and transactions (multi-item, ACID) is essential for choosing the right tool and avoiding common exam traps.
Jump to a section
Imagine a bank with two tellers, Alice and Bob. A customer wants to transfer $100 from savings to checking. The transfer has two phases: first, deduct $100 from savings and mark it as pending; second, add $100 to checking and commit. If the power fails after phase one but before phase two, the money is lost. To prevent this, the bank uses a two-phase commit protocol. The customer hands Alice a withdrawal slip for $100 from savings. Alice places the slip in a 'pending' tray and locks the savings account record so no one else can touch that $100. She then passes the slip to Bob, who adds $100 to checking and locks that record. Only after Bob confirms does Alice release the lock on savings and both tellers finalize the transaction. If Bob cannot complete (e.g., checking account is frozen), Alice reverses the deduction and both records are unlocked. This is exactly how DynamoDB transactions work: a 'Check' phase verifies conditions and locks items, then a 'Commit' phase applies all changes atomically. If any check fails, the entire transaction is rolled back. Without this protocol, concurrent withdrawals could cause overdrafts or lost money.
What Are DynamoDB Transactions and Conditional Writes?
DynamoDB transactions provide ACID (Atomic, Consistent, Isolated, Durable) guarantees across one or more items within a single AWS account and region. They are designed for use cases where you must ensure that multiple items are updated, inserted, or deleted as a single, all-or-nothing operation. Conditional writes, on the other hand, are a lighter-weight mechanism that allows you to perform a write operation (PutItem, UpdateItem, DeleteItem) only if a specified condition is met on a single item. Both are critical for building correct, concurrent applications.
How DynamoDB Transactions Work Internally
DynamoDB transactions use a two-phase commit protocol:
Phase 1 – Check (or Prepare): The transaction request includes a list of actions. DynamoDB first checks all preconditions (conditions specified in each action). For each item involved, DynamoDB acquires a lock on the item's partition (more precisely, on the item within its partition). The lock prevents other transactions or writes from modifying the item until the transaction completes. If any condition fails, DynamoDB releases all locks and returns a TransactionCanceledException with details about which condition failed.
Phase 2 – Commit: If all checks pass, DynamoDB applies the changes to all items atomically. It writes the new values and releases the locks. The entire operation is logged to the transaction log for durability. If a failure occurs during the commit phase (e.g., a node crash), DynamoDB automatically rolls back the transaction using the log.
Locking Behavior: Locks are held for the duration of the transaction, which is typically milliseconds but can be longer under contention. The default transaction timeout is 1 second. If a transaction does not complete within 1 second, it is cancelled and locks are released. This timeout is not configurable.
Throughput Consumption: Transactions consume twice the write capacity units (WCUs) or read capacity units (RCUs) compared to standard writes/reads. For a write transaction, each write consumes 2 WCUs (one for the prepare phase, one for the commit). For a read transaction (e.g., TransactGetItems), each item read consumes 2 RCUs. This is a common exam point.
Conditional Writes – Single-Item Atomicity
Conditional writes are simpler: they allow you to specify a condition expression on a single-item write (PutItem, UpdateItem, DeleteItem). The write proceeds only if the condition evaluates to true. If the condition fails, the operation returns a ConditionalCheckFailedException and no write is performed. Conditions can check attribute values (e.g., attribute_not_exists(id), size > 10), attribute existence, or compare values.
Use Cases: Conditional writes are ideal for optimistic locking. For example, you can update an item only if its version attribute matches a known value. This prevents lost updates in concurrent scenarios.
Important: Conditional writes do not lock the item. They are atomic only at the single-item level. If two concurrent conditional writes check the same condition simultaneously, both may succeed if the condition is true at the time of evaluation. This is a race condition. To avoid this, use transactions or a version number with conditional writes (optimistic locking) and retry on failure.
Key Components and Parameters
Transaction API Operations:
- TransactWriteItems – A batch of up to 25 write actions (Put, Update, Delete) across multiple items. Each action can have its own condition expression.
- TransactGetItems – A batch of up to 25 read actions (Get) across multiple items. Returns consistent read (strongly consistent) by default.
Condition Expression:
- Used in both transactions and conditional writes.
- Syntax: attribute_exists | attribute_not_exists | attribute_type | begins_with | contains | size | comparison operators (=, <>, <, >, <=, >=, BETWEEN, IN).
- Can combine with AND, OR, NOT, and parentheses.
Client Request Token (Idempotency):
- For TransactWriteItems, you can provide a ClientRequestToken (a string) to make the transaction idempotent. If the same token is used within a 10-minute window, DynamoDB will not execute the transaction again but will return the previous result. This is crucial for retry logic.
Transaction Canceled Exception:
- Contains a CancellationReasons list that details which action failed and why (e.g., ConditionalCheckFailed, TransactionConflict, None for successful actions).
Interaction with Related Technologies
DynamoDB Streams: Transactions generate stream records as normal writes/updates/deletes, but the stream records appear only after the transaction commits. If a transaction is rolled back, no stream records are emitted. This is important for downstream processing.
DAX (DynamoDB Accelerator): DAX is an in-memory cache that can be used with conditional writes and transactions? Actually, DAX does not support transactions. You cannot use DAX with TransactWriteItems or TransactGetItems. Also, conditional writes via DAX are not supported – you must use the DynamoDB API directly for conditional operations.
Global Tables: Transactions are supported in global tables, but they are only atomic within a single region. Cross-region transactions are not atomic. If you need atomicity across regions, you must implement your own coordination.
Configuration and Verification
There is no configuration to enable transactions – they are always available. However, you must have the appropriate IAM permissions: dynamodb:TransactWriteItems and dynamodb:TransactGetItems. Also, the table must have sufficient provisioned capacity or handle throttling via on-demand.
CLI Example – TransactWriteItems:
aws dynamodb transact-write-items --transact-items '[
{
"Put": {
"TableName": "Orders",
"Item": {
"OrderID": {"S": "123"},
"CustomerID": {"S": "C456"},
"Total": {"N": "100"}
},
"ConditionExpression": "attribute_not_exists(OrderID)"
}
},
{
"Update": {
"TableName": "Accounts",
"Key": {"AccountID": {"S": "A789"}},
"UpdateExpression": "SET balance = balance - :amount",
"ConditionExpression": "balance >= :amount",
"ExpressionAttributeValues": {
":amount": {"N": "100"}
}
}
}
]'CLI Example – Conditional Write (PutItem):
aws dynamodb put-item \
--table-name Products \
--item '{"ProductID": {"S": "P001"}, "Price": {"N": "25"}}' \
--condition-expression "attribute_not_exists(ProductID)"Error Handling:
- For conditional writes, catch ConditionalCheckFailedException.
- For transactions, catch TransactionCanceledException and inspect CancellationReasons.
Performance Considerations
Transactions have higher latency than individual writes because of the two-phase commit and locking. They also consume more capacity units. Use transactions only when you truly need multi-item atomicity. For single-item atomic updates, use conditional writes with optimistic locking.
Contention: If multiple transactions try to access the same item simultaneously, some will fail with a TransactionConflict exception (part of CancellationReasons). You should implement retry logic with exponential backoff.
Item Size Limit: The maximum item size in DynamoDB is 400 KB. For transactions, the total size of all items in a single transaction cannot exceed 4 MB (for write transactions) and 4 MB for read transactions. This is an exam detail.
Number of Actions: Up to 25 actions per transaction (read or write).
Initialize Transaction Request
The client application constructs a `TransactWriteItems` or `TransactGetItems` request containing up to 25 actions. Each action specifies the table, key, and operation (Put, Update, Delete, or Get). Optionally, each action can include a condition expression. The client may also provide a `ClientRequestToken` for idempotency. The request is sent to the DynamoDB API endpoint over HTTPS.
Phase 1: Check Conditions
DynamoDB receives the request and begins the two-phase commit. In the first phase, it evaluates all condition expressions for each action. For each item involved, DynamoDB acquires a lock on the item's partition (specifically, a lock on the item within the partition). The lock prevents any other writes or transactions from modifying that item. If any condition expression evaluates to false, DynamoDB releases all locks and returns a `TransactionCanceledException` with a list of `CancellationReasons`. The entire transaction is aborted.
Phase 2: Commit Changes
If all conditions pass, DynamoDB proceeds to the commit phase. It applies all the mutations (Put, Update, Delete) to the respective items atomically. The changes are written to the storage nodes and replicated for durability. After the commit, all locks are released. The transaction is considered successful and the client receives a successful response (e.g., `ConsumedCapacity` if requested).
Handle Transaction Timeout
The entire transaction must complete within 1 second (the default transaction timeout). If the commit phase takes longer than 1 second (e.g., due to high contention or throttling), DynamoDB automatically cancels the transaction and releases locks. The client receives a `TransactionCanceledException` with `CancellationReasons` indicating `None` for actions that passed the check but were not committed. The client should retry with exponential backoff.
Retry on Conflict or Throttling
If a transaction fails due to a `TransactionConflict` (i.e., another transaction holds a lock on an item), or due to `ProvisionedThroughputExceededException`, the client should implement retry logic. The recommended approach is exponential backoff with jitter. For idempotent transactions, include the same `ClientRequestToken` in retries to avoid duplicate execution. DynamoDB will return the original result if the token is reused within 10 minutes.
Scenario 1: E-Commerce Order Processing
An e-commerce platform uses DynamoDB to store orders and inventory. When a customer places an order, the system must deduct the quantity from the inventory table and create an order record atomically. Without transactions, if the inventory deduction succeeds but the order creation fails, the inventory is lost. Using TransactWriteItems, the platform includes a Update action on the inventory item (with a condition that stock >= requested quantity) and a Put action on the orders table. If the inventory is insufficient, the entire transaction fails, and no order is created. In production, this system handles thousands of orders per second. The main challenge is contention on popular items – multiple customers may try to order the same item simultaneously, causing TransactionConflict exceptions. The solution is to use optimistic concurrency with a version number and retry logic. The inventory item includes a version attribute; the condition checks that the version hasn't changed. On conflict, the client retries with the new version. This pattern is common in high-traffic e-commerce.
Scenario 2: Financial Ledger System
A fintech company maintains a ledger of account balances in DynamoDB. When a transfer occurs between two accounts, both the debit and credit must happen atomically. Using TransactWriteItems, the system performs an Update on the sender's account (with condition balance >= amount) and an Update on the receiver's account. If the sender has insufficient funds, the transaction fails. In production, the system processes millions of transactions daily. The transaction timeout of 1 second is rarely an issue, but during peak load, throttling can occur. The system uses on-demand capacity to handle spikes. A common mistake is to use separate conditional writes instead of a transaction – this can lead to a scenario where the debit succeeds but the credit fails, causing data inconsistency. The exam tests this exact scenario: when you need atomicity across multiple items, you must use a transaction.
Scenario 3: Multi-User Collaborative Editing
A document editing application stores document revisions in DynamoDB. Multiple users may edit the same document simultaneously. To prevent conflicts, the application uses conditional writes with a version number. Each document item has a version attribute. When a user saves changes, the application issues an UpdateItem with a condition that version == currentVersion. If another user has saved in the meantime, the condition fails, and the application retrieves the latest version and prompts the user to merge. This is an example of optimistic locking. Transactions are not needed here because only one item is updated per save. The exam often contrasts this use case (single-item) with the multi-item atomicity requirement where transactions are necessary.
What DVA-C02 Tests (Objective 1.3)
The exam focuses on distinguishing between conditional writes and transactions, understanding when to use each, and knowing the specific limitations and behaviors. Key objective codes: Domain 1: Development with AWS Services, Objective 1.3: Implement data consistency solutions. Specific subtopics: DynamoDB transactions, conditional writes, optimistic locking, and idempotency.
Common Wrong Answers and Why Candidates Choose Them
Using conditional writes when a transaction is required. Candidates often choose conditional writes for multi-item updates because they are simpler and cheaper. However, conditional writes operate on a single item only. If you need atomicity across multiple items (e.g., debit one account and credit another), a conditional write on each item separately does not guarantee both succeed or both fail. The exam will present a scenario where two items must be updated atomically – the wrong answer will suggest separate conditional writes or a batch write (which is not atomic). The correct answer is a transaction.
Thinking transactions are free or consume 1 WCU per write. Some candidates assume transactions consume the same capacity as regular writes. The exam tests that transactions consume double capacity (2 WCU per write, 2 RCU per read). A question might ask about cost implications – the wrong answer will ignore the double consumption.
Believing transactions lock entire tables. Candidates may think transactions lock all items in the table or partition. In reality, locks are per-item within a partition. Other items in the same partition can be accessed unless they are part of the same transaction. The exam might present a scenario with high contention and ask about performance – the wrong answer might suggest table-level locking.
Assuming transactions are available in DAX. DAX does not support transactions. If a question involves DAX and transactions, the correct answer is to bypass DAX and use the DynamoDB API directly. Candidates may incorrectly think DAX caches transaction results.
Specific Numbers and Terms Verbatim on Exam
- 25 actions per transaction (both read and write).
- 4 MB maximum total item size per transaction.
- 1 second transaction timeout (not configurable).
- 2 WCU per write transaction item, 2 RCU per read transaction item.
- 10-minute idempotency window for ClientRequestToken.
- TransactionCanceledException includes CancellationReasons.
- ConditionalCheckFailedException for failed conditional writes.
Edge Cases and Exceptions
- If a transaction includes a Get action (in TransactWriteItems? Actually, TransactWriteItems does not support Get; only TransactGetItems does. The exam may test that TransactWriteItems only supports Put, Update, Delete. Be careful: TransactGetItems only supports Get. You cannot mix read and write in the same transaction.
- Conditional writes with attribute_not_exists can be used to implement 'insert if not exists' – this is a common pattern for unique constraints.
- Transactions with global tables: atomic only within a region. Cross-region eventual consistency.
How to Eliminate Wrong Answers
- If the scenario requires atomicity across multiple items, eliminate any answer that does not mention TransactWriteItems.
- If the scenario involves a single item and a condition, look for conditional write (PutItem with condition) – not a transaction.
- If the question mentions cost, remember double capacity for transactions.
- If DAX is mentioned, transactions are not possible; use DynamoDB API directly.
DynamoDB transactions provide ACID guarantees across multiple items using a two-phase commit protocol with a 1-second timeout.
Conditional writes are atomic for a single item and are used for optimistic locking or conditional updates without locking.
Transactions consume double the capacity (2 WCU/RCU per item) compared to regular operations.
Transactions support up to 25 actions and a total item size of 4 MB per transaction.
ClientRequestToken enables idempotent transactions within a 10-minute window.
DAX does not support transactions – use DynamoDB API directly for transactional operations.
Global tables support transactions but only within a single region; cross-region atomicity is not guaranteed.
Always use transactions when you need atomicity across multiple items; use conditional writes for single-item conditional operations.
These come up on the exam all the time. Here's how to tell them apart.
Conditional Writes
Operates on a single item only.
Consumes 1 WCU per write (or 1 RCU for reads, but conditional writes are write operations).
No locking mechanism – race conditions possible.
Returns ConditionalCheckFailedException if condition fails.
Supports PutItem, UpdateItem, DeleteItem with condition expression.
DynamoDB Transactions
Operates on up to 25 items across multiple tables.
Consumes 2 WCU per write action, 2 RCU per read action.
Uses locks on items during the two-phase commit.
Returns TransactionCanceledException with CancellationReasons.
Supports TransactWriteItems (Put, Update, Delete) and TransactGetItems (Get).
Mistake
DynamoDB transactions lock the entire table during execution.
Correct
Transactions only lock the specific items involved in the transaction, not the entire table or partition. Other items in the same partition can be read or written by other operations, as long as they are not part of the same transaction.
Mistake
Conditional writes are atomic across multiple items.
Correct
Conditional writes operate on a single item only. They are atomic for that single item, but if you need to update multiple items atomically, you must use a transaction. Separate conditional writes do not provide atomicity across items.
Mistake
Transactions consume the same read/write capacity as regular operations.
Correct
Transactions consume double the capacity: each write action consumes 2 WCUs, and each read action consumes 2 RCUs. This is because of the two-phase commit protocol (prepare and commit phases).
Mistake
You can use DAX with DynamoDB transactions.
Correct
DAX does not support transactions. You cannot use DAX with `TransactWriteItems` or `TransactGetItems`. For transactional operations, you must bypass DAX and call the DynamoDB API directly.
Mistake
The transaction timeout is configurable.
Correct
The transaction timeout is fixed at 1 second and cannot be changed. If a transaction does not complete within 1 second, it is automatically cancelled and locks are released.
Reveal each answer, then mark whether you got it right. Score 60%+ to unlock the next chapter.
A conditional write is an atomic operation on a single item that executes only if a specified condition is met. It does not lock the item and is subject to race conditions. A transaction is a multi-item, ACID-compliant operation that uses a two-phase commit with locks to ensure all actions succeed or fail together. Use conditional writes for single-item optimistic locking; use transactions when you need to update multiple items atomically.
You can include up to 25 actions in a single TransactWriteItems or TransactGetItems call. The total size of all items in the transaction cannot exceed 4 MB. Each action can operate on a different item, potentially in different tables.
The transaction timeout is 1 second. If the transaction does not complete within that time, DynamoDB cancels it and releases any locks. The client receives a TransactionCanceledException with CancellationReasons indicating which actions failed. The client should retry the transaction with exponential backoff.
No, DAX does not support transactions. You cannot use TransactWriteItems or TransactGetItems through DAX. For transactional operations, you must call the DynamoDB API directly. DAX is only for single-item read and write operations.
Optimistic locking is implemented using conditional writes with a version attribute. For example, include an attribute `version` in your item. When updating, use a condition expression like `version = :expectedVersion` and increment the version in the update expression. If the condition fails, another update occurred, and you must retry after reading the latest version.
ClientRequestToken is an optional parameter for TransactWriteItems that makes the transaction idempotent. If you provide the same token within a 10-minute window, DynamoDB will not execute the transaction again but will return the original result. This is critical for retry logic to prevent duplicate operations in case of network failures.
Yes, transactions are supported in global tables, but they are atomic only within a single region. Cross-region atomicity is not guaranteed. If you need atomicity across regions, you must implement your own coordination mechanism.
You've just covered DynamoDB Transactions and Conditional Writes — now see how well it sticks with free DVA-C02 practice questions. Full explanations included, no account needed.
Done with this chapter?