0
# Transactions
1
2
ACID transaction support for complex multi-item operations with strong consistency guarantees. DynamoDB transactions allow you to perform multiple operations across multiple items and tables atomically, ensuring data consistency and integrity.
3
4
## Capabilities
5
6
### Transact Write Items
7
8
Performs a synchronous write operation that groups up to 100 action requests as a single atomic transaction.
9
10
```java { .api }
11
/**
12
* Synchronous write operation that groups up to 100 action requests
13
* @param request - The request containing transaction items and options
14
* @return Response containing consumed capacity and item collection metrics
15
*/
16
TransactWriteItemsResponse transactWriteItems(TransactWriteItemsRequest request);
17
18
class TransactWriteItemsRequest {
19
static Builder builder();
20
21
/** An ordered array of up to 100 TransactWriteItem objects */
22
List<TransactWriteItem> transactItems();
23
Builder transactItems(Collection<TransactWriteItem> transactItems);
24
25
/** Determines the level of detail about consumed capacity returned */
26
ReturnConsumedCapacity returnConsumedCapacity();
27
Builder returnConsumedCapacity(ReturnConsumedCapacity returnConsumedCapacity);
28
29
/** Determines whether item collection metrics are returned */
30
ReturnItemCollectionMetrics returnItemCollectionMetrics();
31
Builder returnItemCollectionMetrics(ReturnItemCollectionMetrics returnItemCollectionMetrics);
32
33
/** Providing a ClientRequestToken makes the call idempotent */
34
String clientRequestToken();
35
Builder clientRequestToken(String clientRequestToken);
36
}
37
38
class TransactWriteItem {
39
static Builder builder();
40
41
/** A request to perform a check item operation */
42
ConditionCheck conditionCheck();
43
Builder conditionCheck(ConditionCheck conditionCheck);
44
45
/** A request to perform a PutItem operation */
46
Put put();
47
Builder put(Put put);
48
49
/** A request to perform a DeleteItem operation */
50
Delete delete();
51
Builder delete(Delete delete);
52
53
/** A request to perform an UpdateItem operation */
54
Update update();
55
Builder update(Update update);
56
}
57
58
class ConditionCheck {
59
static Builder builder();
60
61
/** Name of the table for the check item request */
62
String tableName();
63
Builder tableName(String tableName);
64
65
/** The primary key of the item to be checked */
66
Map<String, AttributeValue> key();
67
Builder key(Map<String, AttributeValue> key);
68
69
/** A condition that must be satisfied to include an item in the response */
70
String conditionExpression();
71
Builder conditionExpression(String conditionExpression);
72
73
/** One or more substitution tokens for attribute names in expressions */
74
Map<String, String> expressionAttributeNames();
75
Builder expressionAttributeNames(Map<String, String> expressionAttributeNames);
76
77
/** One or more values that can be substituted in expressions */
78
Map<String, AttributeValue> expressionAttributeValues();
79
Builder expressionAttributeValues(Map<String, AttributeValue> expressionAttributeValues);
80
81
/** Use ReturnValuesOnConditionCheckFailure to get the item attributes if the condition fails */
82
ReturnValuesOnConditionCheckFailure returnValuesOnConditionCheckFailure();
83
Builder returnValuesOnConditionCheckFailure(ReturnValuesOnConditionCheckFailure returnValuesOnConditionCheckFailure);
84
}
85
86
class Put {
87
static Builder builder();
88
89
/** A map of attribute name/value pairs, one for each attribute */
90
Map<String, AttributeValue> item();
91
Builder item(Map<String, AttributeValue> item);
92
93
/** Name of the table for the put item request */
94
String tableName();
95
Builder tableName(String tableName);
96
97
/** A condition that must be satisfied to include an item in the response */
98
String conditionExpression();
99
Builder conditionExpression(String conditionExpression);
100
101
/** One or more substitution tokens for attribute names in expressions */
102
Map<String, String> expressionAttributeNames();
103
Builder expressionAttributeNames(Map<String, String> expressionAttributeNames);
104
105
/** One or more values that can be substituted in expressions */
106
Map<String, AttributeValue> expressionAttributeValues();
107
Builder expressionAttributeValues(Map<String, AttributeValue> expressionAttributeValues);
108
109
/** Use ReturnValuesOnConditionCheckFailure to get the item attributes if the condition fails */
110
ReturnValuesOnConditionCheckFailure returnValuesOnConditionCheckFailure();
111
Builder returnValuesOnConditionCheckFailure(ReturnValuesOnConditionCheckFailure returnValuesOnConditionCheckFailure);
112
}
113
114
class Delete {
115
static Builder builder();
116
117
/** The primary key of the item to be deleted */
118
Map<String, AttributeValue> key();
119
Builder key(Map<String, AttributeValue> key);
120
121
/** Name of the table for the delete item request */
122
String tableName();
123
Builder tableName(String tableName);
124
125
/** A condition that must be satisfied to include an item in the response */
126
String conditionExpression();
127
Builder conditionExpression(String conditionExpression);
128
129
/** One or more substitution tokens for attribute names in expressions */
130
Map<String, String> expressionAttributeNames();
131
Builder expressionAttributeNames(Map<String, String> expressionAttributeNames);
132
133
/** One or more values that can be substituted in expressions */
134
Map<String, AttributeValue> expressionAttributeValues();
135
Builder expressionAttributeValues(Map<String, AttributeValue> expressionAttributeValues);
136
137
/** Use ReturnValuesOnConditionCheckFailure to get the item attributes if the condition fails */
138
ReturnValuesOnConditionCheckFailure returnValuesOnConditionCheckFailure();
139
Builder returnValuesOnConditionCheckFailure(ReturnValuesOnConditionCheckFailure returnValuesOnConditionCheckFailure);
140
}
141
142
class Update {
143
static Builder builder();
144
145
/** The primary key of the item to be updated */
146
Map<String, AttributeValue> key();
147
Builder key(Map<String, AttributeValue> key);
148
149
/** Name of the table for the update item request */
150
String tableName();
151
Builder tableName(String tableName);
152
153
/** An expression that defines one or more attributes to be updated */
154
String updateExpression();
155
Builder updateExpression(String updateExpression);
156
157
/** A condition that must be satisfied to include an item in the response */
158
String conditionExpression();
159
Builder conditionExpression(String conditionExpression);
160
161
/** One or more substitution tokens for attribute names in expressions */
162
Map<String, String> expressionAttributeNames();
163
Builder expressionAttributeNames(Map<String, String> expressionAttributeNames);
164
165
/** One or more values that can be substituted in expressions */
166
Map<String, AttributeValue> expressionAttributeValues();
167
Builder expressionAttributeValues(Map<String, AttributeValue> expressionAttributeValues);
168
169
/** Use ReturnValuesOnConditionCheckFailure to get the item attributes if the condition fails */
170
ReturnValuesOnConditionCheckFailure returnValuesOnConditionCheckFailure();
171
Builder returnValuesOnConditionCheckFailure(ReturnValuesOnConditionCheckFailure returnValuesOnConditionCheckFailure);
172
}
173
174
class TransactWriteItemsResponse {
175
/** The capacity units consumed by the entire transaction */
176
List<ConsumedCapacity> consumedCapacity();
177
178
/** A list of tables that were processed by TransactWriteItems and their item collection metrics */
179
Map<String, List<ItemCollectionMetrics>> itemCollectionMetrics();
180
}
181
```
182
183
**Usage Example:**
184
185
```java
186
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
187
import software.amazon.awssdk.services.dynamodb.model.*;
188
import java.util.List;
189
import java.util.Map;
190
191
DynamoDbClient client = DynamoDbClient.builder().build();
192
193
// Transfer money between accounts atomically
194
List<TransactWriteItem> transactItems = List.of(
195
// Debit from source account
196
TransactWriteItem.builder()
197
.update(Update.builder()
198
.tableName("Accounts")
199
.key(Map.of("accountId", AttributeValue.builder().s("account1").build()))
200
.updateExpression("SET balance = balance - :amount")
201
.conditionExpression("balance >= :amount") // Ensure sufficient funds
202
.expressionAttributeValues(Map.of(
203
":amount", AttributeValue.builder().n("100.00").build()
204
))
205
.build())
206
.build(),
207
208
// Credit to destination account
209
TransactWriteItem.builder()
210
.update(Update.builder()
211
.tableName("Accounts")
212
.key(Map.of("accountId", AttributeValue.builder().s("account2").build()))
213
.updateExpression("SET balance = balance + :amount")
214
.conditionExpression("attribute_exists(accountId)") // Ensure account exists
215
.expressionAttributeValues(Map.of(
216
":amount", AttributeValue.builder().n("100.00").build()
217
))
218
.build())
219
.build(),
220
221
// Log the transaction
222
TransactWriteItem.builder()
223
.put(Put.builder()
224
.tableName("TransactionLogs")
225
.item(Map.of(
226
"transactionId", AttributeValue.builder().s("txn-123").build(),
227
"fromAccount", AttributeValue.builder().s("account1").build(),
228
"toAccount", AttributeValue.builder().s("account2").build(),
229
"amount", AttributeValue.builder().n("100.00").build(),
230
"timestamp", AttributeValue.builder().s("2025-09-07T17:30:00Z").build()
231
))
232
.conditionExpression("attribute_not_exists(transactionId)") // Prevent duplicates
233
.build())
234
.build()
235
);
236
237
try {
238
TransactWriteItemsResponse response = client.transactWriteItems(
239
TransactWriteItemsRequest.builder()
240
.transactItems(transactItems)
241
.returnConsumedCapacity(ReturnConsumedCapacity.TOTAL)
242
.clientRequestToken("transfer-123") // For idempotency
243
.build()
244
);
245
246
System.out.println("Transaction completed successfully");
247
System.out.println("Total consumed capacity: " +
248
response.consumedCapacity().stream()
249
.mapToDouble(cc -> cc.capacityUnits())
250
.sum());
251
252
} catch (TransactionCanceledException e) {
253
System.err.println("Transaction failed: " + e.getMessage());
254
// Handle transaction failure (e.g., insufficient funds, account doesn't exist)
255
}
256
```
257
258
### Transact Get Items
259
260
Retrieves multiple items from one or more tables in a single atomic operation.
261
262
```java { .api }
263
/**
264
* Synchronous read operation that groups up to 100 Get actions together
265
* @param request - The request containing transaction items and options
266
* @return Response containing retrieved items and consumed capacity
267
*/
268
TransactGetItemsResponse transactGetItems(TransactGetItemsRequest request);
269
270
class TransactGetItemsRequest {
271
static Builder builder();
272
273
/** An ordered array of up to 100 TransactGetItem objects */
274
List<TransactGetItem> transactItems();
275
Builder transactItems(Collection<TransactGetItem> transactItems);
276
277
/** Determines the level of detail about consumed capacity returned */
278
ReturnConsumedCapacity returnConsumedCapacity();
279
Builder returnConsumedCapacity(ReturnConsumedCapacity returnConsumedCapacity);
280
}
281
282
class TransactGetItem {
283
static Builder builder();
284
285
/** Contains the primary key that identifies the item to get */
286
Get get();
287
Builder get(Get get);
288
}
289
290
class Get {
291
static Builder builder();
292
293
/** A map of attribute names to AttributeValue objects that specifies the primary key */
294
Map<String, AttributeValue> key();
295
Builder key(Map<String, AttributeValue> key);
296
297
/** The name of the table from which to retrieve the specified item */
298
String tableName();
299
Builder tableName(String tableName);
300
301
/** A string that identifies one or more attributes of the specified item to retrieve */
302
String projectionExpression();
303
Builder projectionExpression(String projectionExpression);
304
305
/** One or more substitution tokens for attribute names in the ProjectionExpression */
306
Map<String, String> expressionAttributeNames();
307
Builder expressionAttributeNames(Map<String, String> expressionAttributeNames);
308
}
309
310
class TransactGetItemsResponse {
311
/** An ordered array of up to 100 ItemResponse objects */
312
List<ItemResponse> responses();
313
314
/** The capacity units consumed by the entire transaction */
315
List<ConsumedCapacity> consumedCapacity();
316
}
317
318
class ItemResponse {
319
/** Map of attribute data consisting of the data type and attribute value */
320
Map<String, AttributeValue> item();
321
}
322
```
323
324
**Usage Example:**
325
326
```java
327
// Get multiple related items atomically
328
List<TransactGetItem> transactItems = List.of(
329
TransactGetItem.builder()
330
.get(Get.builder()
331
.tableName("Users")
332
.key(Map.of("userId", AttributeValue.builder().s("user123").build()))
333
.projectionExpression("userId, name, email, accountId")
334
.build())
335
.build(),
336
337
TransactGetItem.builder()
338
.get(Get.builder()
339
.tableName("Accounts")
340
.key(Map.of("accountId", AttributeValue.builder().s("acc456").build()))
341
.projectionExpression("accountId, balance, #status")
342
.expressionAttributeNames(Map.of("#status", "status"))
343
.build())
344
.build()
345
);
346
347
TransactGetItemsResponse response = client.transactGetItems(
348
TransactGetItemsRequest.builder()
349
.transactItems(transactItems)
350
.returnConsumedCapacity(ReturnConsumedCapacity.TOTAL)
351
.build()
352
);
353
354
// Process results in order
355
List<ItemResponse> responses = response.responses();
356
Map<String, AttributeValue> user = responses.get(0).item();
357
Map<String, AttributeValue> account = responses.get(1).item();
358
359
if (user != null && account != null) {
360
String userName = user.get("name").s();
361
String balance = account.get("balance").n();
362
System.out.println("User " + userName + " has balance: $" + balance);
363
}
364
```
365
366
### Execute Transaction (PartiQL)
367
368
Execute multiple PartiQL statements as a single atomic transaction.
369
370
```java { .api }
371
/**
372
* Executes multiple PartiQL statements within a transaction block
373
* @param request - The request containing PartiQL statements and options
374
* @return Response containing statement results and consumed capacity
375
*/
376
ExecuteTransactionResponse executeTransaction(ExecuteTransactionRequest request);
377
378
class ExecuteTransactionRequest {
379
static Builder builder();
380
381
/** The list of PartiQL statements representing the transaction to run */
382
List<ParameterizedStatement> transactStatements();
383
Builder transactStatements(Collection<ParameterizedStatement> transactStatements);
384
385
/** Set this value to get remaining results, if NextToken was returned in the previous response */
386
String nextToken();
387
Builder nextToken(String nextToken);
388
389
/** Providing a ClientRequestToken makes the call idempotent */
390
String clientRequestToken();
391
Builder clientRequestToken(String clientRequestToken);
392
393
/** Determines the level of detail about consumed capacity returned */
394
ReturnConsumedCapacity returnConsumedCapacity();
395
Builder returnConsumedCapacity(ReturnConsumedCapacity returnConsumedCapacity);
396
}
397
398
class ParameterizedStatement {
399
static Builder builder();
400
401
/** A PartiQL statement that can be run against a DynamoDB table */
402
String statement();
403
Builder statement(String statement);
404
405
/** The parameter values for the PartiQL statement, if any */
406
List<AttributeValue> parameters();
407
Builder parameters(Collection<AttributeValue> parameters);
408
409
/** An optional parameter for the ReturnValues on this PartiQL statement */
410
ReturnValuesOnConditionCheckFailure returnValuesOnConditionCheckFailure();
411
Builder returnValuesOnConditionCheckFailure(ReturnValuesOnConditionCheckFailure returnValuesOnConditionCheckFailure);
412
}
413
414
class ExecuteTransactionResponse {
415
/** The response to a PartiQL transaction */
416
List<ItemResponse> responses();
417
418
/** The capacity units consumed by the entire transaction */
419
List<ConsumedCapacity> consumedCapacity();
420
}
421
```
422
423
**Usage Example:**
424
425
```java
426
// Execute multiple PartiQL statements in a transaction
427
List<ParameterizedStatement> statements = List.of(
428
ParameterizedStatement.builder()
429
.statement("UPDATE \"Accounts\" SET balance = balance - ? WHERE accountId = ? AND balance >= ?")
430
.parameters(List.of(
431
AttributeValue.builder().n("100.00").build(), // amount to debit
432
AttributeValue.builder().s("account1").build(), // account ID
433
AttributeValue.builder().n("100.00").build() // minimum balance check
434
))
435
.build(),
436
437
ParameterizedStatement.builder()
438
.statement("UPDATE \"Accounts\" SET balance = balance + ? WHERE accountId = ?")
439
.parameters(List.of(
440
AttributeValue.builder().n("100.00").build(), // amount to credit
441
AttributeValue.builder().s("account2").build() // account ID
442
))
443
.build(),
444
445
ParameterizedStatement.builder()
446
.statement("INSERT INTO \"TransactionLogs\" VALUE {'transactionId': ?, 'amount': ?, 'status': ?}")
447
.parameters(List.of(
448
AttributeValue.builder().s("txn-456").build(),
449
AttributeValue.builder().n("100.00").build(),
450
AttributeValue.builder().s("completed").build()
451
))
452
.build()
453
);
454
455
try {
456
ExecuteTransactionResponse response = client.executeTransaction(
457
ExecuteTransactionRequest.builder()
458
.transactStatements(statements)
459
.clientRequestToken("partiql-txn-456")
460
.returnConsumedCapacity(ReturnConsumedCapacity.TOTAL)
461
.build()
462
);
463
464
System.out.println("PartiQL transaction completed successfully");
465
466
} catch (TransactionCanceledException e) {
467
System.err.println("PartiQL transaction failed: " + e.getMessage());
468
}
469
```
470
471
## Transaction Error Handling
472
473
### Common Transaction Exceptions
474
475
```java { .api }
476
class TransactionCanceledException extends DynamoDbException {
477
/** List of cancellation reasons for each item */
478
List<CancellationReason> cancellationReasons();
479
}
480
481
class TransactionConflictException extends DynamoDbException;
482
483
class TransactionInProgressException extends DynamoDbException;
484
485
class CancellationReason {
486
/** Status code for the result of the cancellation */
487
String code();
488
489
/** Descriptive message for the cancellation */
490
String message();
491
492
/** Item in the request which caused the transaction to get cancelled */
493
Map<String, AttributeValue> item();
494
}
495
```
496
497
**Error Handling Example:**
498
499
```java
500
try {
501
client.transactWriteItems(request);
502
} catch (TransactionCanceledException e) {
503
List<CancellationReason> reasons = e.cancellationReasons();
504
for (int i = 0; i < reasons.size(); i++) {
505
CancellationReason reason = reasons.get(i);
506
if (reason.code() != null) {
507
System.err.println("Item " + i + " failed: " + reason.code() + " - " + reason.message());
508
}
509
}
510
} catch (ValidationException e) {
511
System.err.println("Invalid transaction request: " + e.getMessage());
512
} catch (ProvisionedThroughputExceededException e) {
513
System.err.println("Throughput exceeded, retry with backoff");
514
}
515
```
516
517
## Transaction Best Practices
518
519
### Idempotency
520
521
Always use `clientRequestToken` for idempotent transactions:
522
523
```java
524
String requestToken = UUID.randomUUID().toString();
525
TransactWriteItemsRequest request = TransactWriteItemsRequest.builder()
526
.transactItems(items)
527
.clientRequestToken(requestToken) // Ensures idempotency
528
.build();
529
```
530
531
### Conditional Logic
532
533
Use condition expressions to ensure data integrity:
534
535
```java
536
// Only update if current value meets criteria
537
Update.builder()
538
.updateExpression("SET balance = balance - :amount")
539
.conditionExpression("balance >= :amount AND #status = :active")
540
.expressionAttributeNames(Map.of("#status", "status"))
541
.expressionAttributeValues(Map.of(
542
":amount", AttributeValue.builder().n("100").build(),
543
":active", AttributeValue.builder().s("ACTIVE").build()
544
))
545
.build()
546
```
547
548
### Error Recovery
549
550
Handle partial failures and implement retry logic:
551
552
```java
553
try {
554
client.transactWriteItems(request);
555
} catch (TransactionCanceledException e) {
556
// Analyze cancellation reasons
557
// Implement appropriate retry or compensation logic
558
handleTransactionFailure(e.cancellationReasons());
559
}
560
```