DynamoDB Transactions
A transaction is a group of operations that either all succeed or all fail together. DynamoDB supports ACID transactions — meaning operations across multiple items or even multiple tables happen atomically, consistently, in isolation, and durably.
Why Transactions Are Needed
Many real-world operations involve multiple database changes that must stay in sync. If one step fails, all other steps must be rolled back — otherwise your data ends up in an inconsistent state.
Classic Example: Bank Transfer
Transfer ₹5,000 from Account A to Account B Step 1: Deduct ₹5,000 from Account A Step 2: Add ₹5,000 to Account B What if Step 1 succeeds but Step 2 fails (network error)? → ₹5,000 disappears from Account A but never arrives in Account B → Money is lost from the system With a transaction: → Both steps succeed or both fail → If Step 2 fails, Step 1 is rolled back automatically → No money is ever lost
DynamoDB ACID Guarantees
| Property | What It Means in DynamoDB |
|---|---|
| Atomicity | All operations in the transaction succeed, or none do |
| Consistency | Data remains valid before and after the transaction |
| Isolation | Other operations cannot see partially completed transactions |
| Durability | Committed transactions persist even if the system crashes |
Transaction API Calls
DynamoDB provides two transaction API calls:
- TransactWriteItems — performs writes (Put, Update, Delete, ConditionCheck) atomically
- TransactGetItems — performs reads atomically, returning a consistent snapshot
TransactWriteItems
Combines up to 100 operations across up to 100 items. Items can be in the same table or different tables. All operations either commit together or none of them apply.
Supported Actions in TransactWriteItems
- Put — Insert or replace an item
- Update — Modify attributes of an item
- Delete — Remove an item
- ConditionCheck — Check a condition on an item without modifying it; causes the whole transaction to fail if the condition is false
Example: Order Placement Transaction
When a customer places an order, three things must happen atomically: the order must be created, the product's inventory must decrease, and the user's order count must increase.
TransactWriteItems:
[
{
Put: {
TableName: "Orders",
Item: {
OrderID: "ORD999",
UserID: "U001",
ProductID: "P100",
Status: "Confirmed"
},
ConditionExpression: "attribute_not_exists(OrderID)"
}
},
{
Update: {
TableName: "Products",
Key: { ProductID: "P100" },
UpdateExpression: "SET Stock = Stock - :qty",
ConditionExpression: "Stock >= :qty",
ExpressionAttributeValues: { ":qty": { "N": "1" } }
}
},
{
Update: {
TableName: "Users",
Key: { UserID: "U001" },
UpdateExpression: "ADD OrderCount :inc",
ExpressionAttributeValues: { ":inc": { "N": "1" } }
}
}
]
If the product is out of stock (condition on Stock fails), the entire transaction fails. The order is not created, the stock is not decremented, and the order count is not incremented. The database stays consistent.
TransactGetItems
Reads up to 100 items from one or more tables in a single, consistent snapshot. All items are read at the same point in time — no item reflects a change that was committed after the transaction started.
TransactGetItems:
[
{ Get: { TableName: "Accounts", Key: { AccountID: "A001" } } },
{ Get: { TableName: "Accounts", Key: { AccountID: "A002" } } }
]
Result: Both account balances reflect the same moment in time
No partial updates visible — true consistent read
Transaction Costs
Transactions cost exactly twice the normal operation cost:
- Each write in a transaction costs 2 WCUs instead of 1
- Each read in a transaction costs 2 RCUs instead of 1
The extra cost covers the two-phase commit protocol DynamoDB uses internally to guarantee atomicity.
Transaction Conflict Detection
If two transactions try to modify the same item at the same time, one of them gets a TransactionConflictException. Your application must catch this error and retry the transaction. DynamoDB does not automatically retry conflicting transactions.
Transaction X: Update item I100 (starts at T=0, commits at T=50ms) Transaction Y: Update item I100 (starts at T=10ms) At T=10ms, DynamoDB detects that I100 is locked by Transaction X → Transaction Y fails with TransactionConflictException → Your code retries Transaction Y after Transaction X commits
Idempotent Transactions with Client Token
Network failures can cause uncertainty — did the transaction succeed before the connection dropped? DynamoDB supports a Client Request Token in TransactWriteItems. If you retry the same request with the same token within 10 minutes, DynamoDB returns the original result instead of executing the transaction again. This prevents accidental duplicate transactions on retry.
First attempt: ClientRequestToken = "token-abc" → Transaction commits Network drops. Did it succeed? Second attempt: ClientRequestToken = "token-abc" → DynamoDB says "already done" ✓ No duplicate order, no duplicate stock decrement
Transaction Limits
| Limit | Value |
|---|---|
| Max operations per transaction | 100 |
| Max total data per transaction | 4 MB |
| Tables in one TransactWriteItems | Multiple (across tables allowed) |
| Cost vs single operations | 2× the WCU or RCU cost |
When to Use Transactions
- Financial operations where multiple accounts must update together
- Order placement that requires simultaneous stock reduction
- Game state updates where multiple records must change atomically
- Any operation where partial success is worse than total failure
When Not to Use Transactions
Transactions add cost and latency. Avoid them for single-item updates, situations where eventual consistency is acceptable, or high-volume write paths where the 2× cost would be prohibitive. Use conditional writes (single-item transactions) instead wherever possible.
