CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-software-amazon-awssdk--dynamodb

AWS SDK for Java v2 DynamoDB client library for interacting with Amazon DynamoDB NoSQL database service

Overview
Eval results
Files

transactions.mddocs/

Transactions

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.

Capabilities

Transact Write Items

Performs a synchronous write operation that groups up to 100 action requests as a single atomic transaction.

/**
 * Synchronous write operation that groups up to 100 action requests
 * @param request - The request containing transaction items and options
 * @return Response containing consumed capacity and item collection metrics
 */
TransactWriteItemsResponse transactWriteItems(TransactWriteItemsRequest request);

class TransactWriteItemsRequest {
    static Builder builder();
    
    /** An ordered array of up to 100 TransactWriteItem objects */
    List<TransactWriteItem> transactItems();
    Builder transactItems(Collection<TransactWriteItem> transactItems);
    
    /** Determines the level of detail about consumed capacity returned */
    ReturnConsumedCapacity returnConsumedCapacity();
    Builder returnConsumedCapacity(ReturnConsumedCapacity returnConsumedCapacity);
    
    /** Determines whether item collection metrics are returned */
    ReturnItemCollectionMetrics returnItemCollectionMetrics();
    Builder returnItemCollectionMetrics(ReturnItemCollectionMetrics returnItemCollectionMetrics);
    
    /** Providing a ClientRequestToken makes the call idempotent */
    String clientRequestToken();
    Builder clientRequestToken(String clientRequestToken);
}

class TransactWriteItem {
    static Builder builder();
    
    /** A request to perform a check item operation */
    ConditionCheck conditionCheck();
    Builder conditionCheck(ConditionCheck conditionCheck);
    
    /** A request to perform a PutItem operation */
    Put put();
    Builder put(Put put);
    
    /** A request to perform a DeleteItem operation */
    Delete delete();
    Builder delete(Delete delete);
    
    /** A request to perform an UpdateItem operation */
    Update update();
    Builder update(Update update);
}

class ConditionCheck {
    static Builder builder();
    
    /** Name of the table for the check item request */
    String tableName();
    Builder tableName(String tableName);
    
    /** The primary key of the item to be checked */
    Map<String, AttributeValue> key();
    Builder key(Map<String, AttributeValue> key);
    
    /** A condition that must be satisfied to include an item in the response */
    String conditionExpression();
    Builder conditionExpression(String conditionExpression);
    
    /** One or more substitution tokens for attribute names in expressions */
    Map<String, String> expressionAttributeNames();
    Builder expressionAttributeNames(Map<String, String> expressionAttributeNames);
    
    /** One or more values that can be substituted in expressions */
    Map<String, AttributeValue> expressionAttributeValues();
    Builder expressionAttributeValues(Map<String, AttributeValue> expressionAttributeValues);
    
    /** Use ReturnValuesOnConditionCheckFailure to get the item attributes if the condition fails */
    ReturnValuesOnConditionCheckFailure returnValuesOnConditionCheckFailure();
    Builder returnValuesOnConditionCheckFailure(ReturnValuesOnConditionCheckFailure returnValuesOnConditionCheckFailure);
}

class Put {
    static Builder builder();
    
    /** A map of attribute name/value pairs, one for each attribute */
    Map<String, AttributeValue> item();
    Builder item(Map<String, AttributeValue> item);
    
    /** Name of the table for the put item request */
    String tableName();
    Builder tableName(String tableName);
    
    /** A condition that must be satisfied to include an item in the response */
    String conditionExpression();
    Builder conditionExpression(String conditionExpression);
    
    /** One or more substitution tokens for attribute names in expressions */
    Map<String, String> expressionAttributeNames();
    Builder expressionAttributeNames(Map<String, String> expressionAttributeNames);
    
    /** One or more values that can be substituted in expressions */
    Map<String, AttributeValue> expressionAttributeValues();
    Builder expressionAttributeValues(Map<String, AttributeValue> expressionAttributeValues);
    
    /** Use ReturnValuesOnConditionCheckFailure to get the item attributes if the condition fails */
    ReturnValuesOnConditionCheckFailure returnValuesOnConditionCheckFailure();
    Builder returnValuesOnConditionCheckFailure(ReturnValuesOnConditionCheckFailure returnValuesOnConditionCheckFailure);
}

class Delete {
    static Builder builder();
    
    /** The primary key of the item to be deleted */
    Map<String, AttributeValue> key();
    Builder key(Map<String, AttributeValue> key);
    
    /** Name of the table for the delete item request */
    String tableName();
    Builder tableName(String tableName);
    
    /** A condition that must be satisfied to include an item in the response */
    String conditionExpression();
    Builder conditionExpression(String conditionExpression);
    
    /** One or more substitution tokens for attribute names in expressions */
    Map<String, String> expressionAttributeNames();
    Builder expressionAttributeNames(Map<String, String> expressionAttributeNames);
    
    /** One or more values that can be substituted in expressions */
    Map<String, AttributeValue> expressionAttributeValues();
    Builder expressionAttributeValues(Map<String, AttributeValue> expressionAttributeValues);
    
    /** Use ReturnValuesOnConditionCheckFailure to get the item attributes if the condition fails */
    ReturnValuesOnConditionCheckFailure returnValuesOnConditionCheckFailure();
    Builder returnValuesOnConditionCheckFailure(ReturnValuesOnConditionCheckFailure returnValuesOnConditionCheckFailure);
}

class Update {
    static Builder builder();
    
    /** The primary key of the item to be updated */
    Map<String, AttributeValue> key();
    Builder key(Map<String, AttributeValue> key);
    
    /** Name of the table for the update item request */
    String tableName();
    Builder tableName(String tableName);
    
    /** An expression that defines one or more attributes to be updated */
    String updateExpression();
    Builder updateExpression(String updateExpression);
    
    /** A condition that must be satisfied to include an item in the response */
    String conditionExpression();
    Builder conditionExpression(String conditionExpression);
    
    /** One or more substitution tokens for attribute names in expressions */
    Map<String, String> expressionAttributeNames();
    Builder expressionAttributeNames(Map<String, String> expressionAttributeNames);
    
    /** One or more values that can be substituted in expressions */
    Map<String, AttributeValue> expressionAttributeValues();
    Builder expressionAttributeValues(Map<String, AttributeValue> expressionAttributeValues);
    
    /** Use ReturnValuesOnConditionCheckFailure to get the item attributes if the condition fails */
    ReturnValuesOnConditionCheckFailure returnValuesOnConditionCheckFailure();
    Builder returnValuesOnConditionCheckFailure(ReturnValuesOnConditionCheckFailure returnValuesOnConditionCheckFailure);
}

class TransactWriteItemsResponse {
    /** The capacity units consumed by the entire transaction */
    List<ConsumedCapacity> consumedCapacity();
    
    /** A list of tables that were processed by TransactWriteItems and their item collection metrics */
    Map<String, List<ItemCollectionMetrics>> itemCollectionMetrics();
}

Usage Example:

import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.*;
import java.util.List;
import java.util.Map;

DynamoDbClient client = DynamoDbClient.builder().build();

// Transfer money between accounts atomically
List<TransactWriteItem> transactItems = List.of(
    // Debit from source account
    TransactWriteItem.builder()
        .update(Update.builder()
            .tableName("Accounts")
            .key(Map.of("accountId", AttributeValue.builder().s("account1").build()))
            .updateExpression("SET balance = balance - :amount")
            .conditionExpression("balance >= :amount")  // Ensure sufficient funds
            .expressionAttributeValues(Map.of(
                ":amount", AttributeValue.builder().n("100.00").build()
            ))
            .build())
        .build(),
    
    // Credit to destination account
    TransactWriteItem.builder()
        .update(Update.builder()
            .tableName("Accounts")
            .key(Map.of("accountId", AttributeValue.builder().s("account2").build()))
            .updateExpression("SET balance = balance + :amount")
            .conditionExpression("attribute_exists(accountId)")  // Ensure account exists
            .expressionAttributeValues(Map.of(
                ":amount", AttributeValue.builder().n("100.00").build()
            ))
            .build())
        .build(),
    
    // Log the transaction
    TransactWriteItem.builder()
        .put(Put.builder()
            .tableName("TransactionLogs")
            .item(Map.of(
                "transactionId", AttributeValue.builder().s("txn-123").build(),
                "fromAccount", AttributeValue.builder().s("account1").build(),
                "toAccount", AttributeValue.builder().s("account2").build(),
                "amount", AttributeValue.builder().n("100.00").build(),
                "timestamp", AttributeValue.builder().s("2025-09-07T17:30:00Z").build()
            ))
            .conditionExpression("attribute_not_exists(transactionId)")  // Prevent duplicates
            .build())
        .build()
);

try {
    TransactWriteItemsResponse response = client.transactWriteItems(
        TransactWriteItemsRequest.builder()
            .transactItems(transactItems)
            .returnConsumedCapacity(ReturnConsumedCapacity.TOTAL)
            .clientRequestToken("transfer-123")  // For idempotency
            .build()
    );
    
    System.out.println("Transaction completed successfully");
    System.out.println("Total consumed capacity: " + 
        response.consumedCapacity().stream()
            .mapToDouble(cc -> cc.capacityUnits())
            .sum());
            
} catch (TransactionCanceledException e) {
    System.err.println("Transaction failed: " + e.getMessage());
    // Handle transaction failure (e.g., insufficient funds, account doesn't exist)
}

Transact Get Items

Retrieves multiple items from one or more tables in a single atomic operation.

/**
 * Synchronous read operation that groups up to 100 Get actions together
 * @param request - The request containing transaction items and options
 * @return Response containing retrieved items and consumed capacity
 */
TransactGetItemsResponse transactGetItems(TransactGetItemsRequest request);

class TransactGetItemsRequest {
    static Builder builder();
    
    /** An ordered array of up to 100 TransactGetItem objects */
    List<TransactGetItem> transactItems();
    Builder transactItems(Collection<TransactGetItem> transactItems);
    
    /** Determines the level of detail about consumed capacity returned */
    ReturnConsumedCapacity returnConsumedCapacity();
    Builder returnConsumedCapacity(ReturnConsumedCapacity returnConsumedCapacity);
}

class TransactGetItem {
    static Builder builder();
    
    /** Contains the primary key that identifies the item to get */
    Get get();
    Builder get(Get get);
}

class Get {
    static Builder builder();
    
    /** A map of attribute names to AttributeValue objects that specifies the primary key */
    Map<String, AttributeValue> key();
    Builder key(Map<String, AttributeValue> key);
    
    /** The name of the table from which to retrieve the specified item */
    String tableName();
    Builder tableName(String tableName);
    
    /** A string that identifies one or more attributes of the specified item to retrieve */
    String projectionExpression();
    Builder projectionExpression(String projectionExpression);
    
    /** One or more substitution tokens for attribute names in the ProjectionExpression */
    Map<String, String> expressionAttributeNames();
    Builder expressionAttributeNames(Map<String, String> expressionAttributeNames);
}

class TransactGetItemsResponse {
    /** An ordered array of up to 100 ItemResponse objects */
    List<ItemResponse> responses();
    
    /** The capacity units consumed by the entire transaction */
    List<ConsumedCapacity> consumedCapacity();
}

class ItemResponse {
    /** Map of attribute data consisting of the data type and attribute value */
    Map<String, AttributeValue> item();
}

Usage Example:

// Get multiple related items atomically
List<TransactGetItem> transactItems = List.of(
    TransactGetItem.builder()
        .get(Get.builder()
            .tableName("Users")
            .key(Map.of("userId", AttributeValue.builder().s("user123").build()))
            .projectionExpression("userId, name, email, accountId")
            .build())
        .build(),
    
    TransactGetItem.builder()
        .get(Get.builder()
            .tableName("Accounts") 
            .key(Map.of("accountId", AttributeValue.builder().s("acc456").build()))
            .projectionExpression("accountId, balance, #status")
            .expressionAttributeNames(Map.of("#status", "status"))
            .build())
        .build()
);

TransactGetItemsResponse response = client.transactGetItems(
    TransactGetItemsRequest.builder()
        .transactItems(transactItems)
        .returnConsumedCapacity(ReturnConsumedCapacity.TOTAL)
        .build()
);

// Process results in order
List<ItemResponse> responses = response.responses();
Map<String, AttributeValue> user = responses.get(0).item();
Map<String, AttributeValue> account = responses.get(1).item();

if (user != null && account != null) {
    String userName = user.get("name").s();
    String balance = account.get("balance").n();
    System.out.println("User " + userName + " has balance: $" + balance);
}

Execute Transaction (PartiQL)

Execute multiple PartiQL statements as a single atomic transaction.

/**
 * Executes multiple PartiQL statements within a transaction block
 * @param request - The request containing PartiQL statements and options
 * @return Response containing statement results and consumed capacity
 */
ExecuteTransactionResponse executeTransaction(ExecuteTransactionRequest request);

class ExecuteTransactionRequest {
    static Builder builder();
    
    /** The list of PartiQL statements representing the transaction to run */
    List<ParameterizedStatement> transactStatements();
    Builder transactStatements(Collection<ParameterizedStatement> transactStatements);
    
    /** Set this value to get remaining results, if NextToken was returned in the previous response */
    String nextToken();
    Builder nextToken(String nextToken);
    
    /** Providing a ClientRequestToken makes the call idempotent */
    String clientRequestToken();
    Builder clientRequestToken(String clientRequestToken);
    
    /** Determines the level of detail about consumed capacity returned */
    ReturnConsumedCapacity returnConsumedCapacity();
    Builder returnConsumedCapacity(ReturnConsumedCapacity returnConsumedCapacity);
}

class ParameterizedStatement {
    static Builder builder();
    
    /** A PartiQL statement that can be run against a DynamoDB table */
    String statement();
    Builder statement(String statement);
    
    /** The parameter values for the PartiQL statement, if any */
    List<AttributeValue> parameters();
    Builder parameters(Collection<AttributeValue> parameters);
    
    /** An optional parameter for the ReturnValues on this PartiQL statement */
    ReturnValuesOnConditionCheckFailure returnValuesOnConditionCheckFailure();
    Builder returnValuesOnConditionCheckFailure(ReturnValuesOnConditionCheckFailure returnValuesOnConditionCheckFailure);
}

class ExecuteTransactionResponse {
    /** The response to a PartiQL transaction */
    List<ItemResponse> responses();
    
    /** The capacity units consumed by the entire transaction */
    List<ConsumedCapacity> consumedCapacity();
}

Usage Example:

// Execute multiple PartiQL statements in a transaction
List<ParameterizedStatement> statements = List.of(
    ParameterizedStatement.builder()
        .statement("UPDATE \"Accounts\" SET balance = balance - ? WHERE accountId = ? AND balance >= ?")
        .parameters(List.of(
            AttributeValue.builder().n("100.00").build(),  // amount to debit
            AttributeValue.builder().s("account1").build(),  // account ID
            AttributeValue.builder().n("100.00").build()   // minimum balance check
        ))
        .build(),
    
    ParameterizedStatement.builder()
        .statement("UPDATE \"Accounts\" SET balance = balance + ? WHERE accountId = ?")
        .parameters(List.of(
            AttributeValue.builder().n("100.00").build(),  // amount to credit
            AttributeValue.builder().s("account2").build()  // account ID
        ))
        .build(),
    
    ParameterizedStatement.builder()
        .statement("INSERT INTO \"TransactionLogs\" VALUE {'transactionId': ?, 'amount': ?, 'status': ?}")
        .parameters(List.of(
            AttributeValue.builder().s("txn-456").build(),
            AttributeValue.builder().n("100.00").build(),
            AttributeValue.builder().s("completed").build()
        ))
        .build()
);

try {
    ExecuteTransactionResponse response = client.executeTransaction(
        ExecuteTransactionRequest.builder()
            .transactStatements(statements)
            .clientRequestToken("partiql-txn-456")
            .returnConsumedCapacity(ReturnConsumedCapacity.TOTAL)
            .build()
    );
    
    System.out.println("PartiQL transaction completed successfully");
    
} catch (TransactionCanceledException e) {
    System.err.println("PartiQL transaction failed: " + e.getMessage());
}

Transaction Error Handling

Common Transaction Exceptions

class TransactionCanceledException extends DynamoDbException {
    /** List of cancellation reasons for each item */
    List<CancellationReason> cancellationReasons();
}

class TransactionConflictException extends DynamoDbException;

class TransactionInProgressException extends DynamoDbException;

class CancellationReason {
    /** Status code for the result of the cancellation */
    String code();
    
    /** Descriptive message for the cancellation */  
    String message();
    
    /** Item in the request which caused the transaction to get cancelled */
    Map<String, AttributeValue> item();
}

Error Handling Example:

try {
    client.transactWriteItems(request);
} catch (TransactionCanceledException e) {
    List<CancellationReason> reasons = e.cancellationReasons();
    for (int i = 0; i < reasons.size(); i++) {
        CancellationReason reason = reasons.get(i);
        if (reason.code() != null) {
            System.err.println("Item " + i + " failed: " + reason.code() + " - " + reason.message());
        }
    }
} catch (ValidationException e) {
    System.err.println("Invalid transaction request: " + e.getMessage());
} catch (ProvisionedThroughputExceededException e) {
    System.err.println("Throughput exceeded, retry with backoff");
}

Transaction Best Practices

Idempotency

Always use clientRequestToken for idempotent transactions:

String requestToken = UUID.randomUUID().toString();
TransactWriteItemsRequest request = TransactWriteItemsRequest.builder()
    .transactItems(items)
    .clientRequestToken(requestToken)  // Ensures idempotency
    .build();

Conditional Logic

Use condition expressions to ensure data integrity:

// Only update if current value meets criteria
Update.builder()
    .updateExpression("SET balance = balance - :amount")
    .conditionExpression("balance >= :amount AND #status = :active")
    .expressionAttributeNames(Map.of("#status", "status"))
    .expressionAttributeValues(Map.of(
        ":amount", AttributeValue.builder().n("100").build(),
        ":active", AttributeValue.builder().s("ACTIVE").build()
    ))
    .build()

Error Recovery

Handle partial failures and implement retry logic:

try {
    client.transactWriteItems(request);
} catch (TransactionCanceledException e) {
    // Analyze cancellation reasons
    // Implement appropriate retry or compensation logic
    handleTransactionFailure(e.cancellationReasons());
}

Install with Tessl CLI

npx tessl i tessl/maven-software-amazon-awssdk--dynamodb

docs

backup-restore.md

data-operations.md

global-tables.md

import-export.md

index.md

partiql.md

table-management.md

transactions.md

tile.json