How to Use AWS DynamoDB BatchWriteItem and BatchGetItem in Java Spring Boot Applications | Learn Java Skills

Imran Shaikh
0

AWS DynamoDB's BatchWriteItem and BatchGetItem operations offer efficient ways to interact with multiple items in a single request, enhancing performance and reducing network overhead compared to individual item operations.

The complete code for this project is available on my GitHub repository (getButton) #text=(GitHub) #icon=(share) #color=(#000000)

toc
batchwriteitem and batchgetitem thumbnail image

Interacting with DynamoDB Using Java


The AWS SDK for Java provides interface like DynamoDbClient and DynamoDbAsyncClient to interact with the DynamoDB database. These clients offer methods for various DynamoDB operations, including getItem, putItem, batchGetItem, and batchWriteItem


Spring Boot simplifies DynamoDB interaction by auto-configuring the DynamoDbClient based on settings in your application properties file when using the Spring Cloud AWS Starter DynamoDB


Dependencies: Gradle


 // spring cloud aws BOM(Bill of materials)
 implementation platform("io.awspring.cloud:spring-cloud-aws-dependencies:${springCloudAwsVersion}")
 // dynamoDB
 implementation 'io.awspring.cloud:spring-cloud-aws-starter-dynamodb'

Setting Up DynamoDB for Your Application: application.properties


If you're new to Spring Cloud AWS and DynamoDB, I recommend reading our (getButton) #text=(Spring Boot, DynamoDB, and Spring Cloud AWS: A Step-by-Step Tutorial) #icon=(link) #color=(#35a576), which will help you build up your project and get deep into the CRUD (Create, Read, Update, and Delete) operations.


 spring.application.name=spring-cloud-aws-dynamodb

 # DynamoDB connection
 spring.cloud.aws.credentials.access-key=
 spring.cloud.aws.credentials.secret-key=
 # Choose your region according to your table. Because I have a DynamoDB table in the ap-south-1 area, I've set the endpoint and region.
 spring.cloud.aws.region.static=ap-south-1
 spring.cloud.aws.endpoint=https://dynamodb.ap-south-1.amazonaws.com

DynamoDB BatchWriteItem: Efficiently Writing Multiple Items to DynamoDB


The BatchWriteItem approach puts or deletes multiple items into one or more tables. A single call to BatchWriteItem may send up to 16MB of data across the network, which includes up to 25 item put or delete operations.


While individual items can be up to 400 KB once saved, it's crucial to remember that an item's representation may be bigger than 400 KB when submitted in DynamoDB's JSON format for the API request.

BatchWriteItem cannot update items. If you run a BatchWriteItem action on an existing item, the operation will overwrite the item's values, making it look as if it was changed. To update things, AWS recommend using the UpdateItem action.(alert-warning)

Java Program to Perform BatchWriteItems Operations on DynamoDB

This Java program demonstrates how to efficiently insert data into multiple DynamoDB tables using the BatchWriteItem operation. We'll create sample data for Orders and products tables and insert them in a single batch for improved performance.


package in.learnjavaskills.springcloudawsdynamodb.service;

import org.springframework.stereotype.Service;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.*;

import java.time.LocalDate;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
public class BatchItemExample
{
    private final DynamoDbClient dynamoDbClient;

    public BatchItemExample(DynamoDbClient dynamoDbClient) {
        this.dynamoDbClient = dynamoDbClient;
    }

    public void batchWriteItem() {
        Map<String, AttributeValue> productsMap = new HashMap<>();
        productsMap.put("product_id", AttributeValue.fromS("pd_12345"));
        productsMap.put("product_name", AttributeValue.fromS("Laptop"));
        productsMap.put("description", AttributeValue.fromS("14 inch screen laptop"));
        productsMap.put("price", AttributeValue.fromN("49.87"));
        productsMap.put("stock", AttributeValue.fromN("101"));

        PutRequest productsPutRequest = PutRequest.builder().item(productsMap).build();
        WriteRequest productsWriteRequest = WriteRequest.builder().putRequest(productsPutRequest).build();

        Map<String, AttributeValue> ordersMap = new HashMap<>();
        ordersMap.put("order_id", AttributeValue.fromS("od_12345"));
        ordersMap.put("customer_id", AttributeValue.fromS("c_12345"));
        ordersMap.put("product_id", AttributeValue.fromS("pd_12345"));
        ordersMap.put("order_date", AttributeValue.fromS(LocalDate.now().toString()));

        PutRequest orderPutRequest = PutRequest.builder().item(ordersMap).build();
        WriteRequest orderWriteRequest = WriteRequest.builder().putRequest(orderPutRequest).build();

        Map<String, List<WriteRequest>> writeRequestMap = new HashMap<>();
        writeRequestMap.put("products", Arrays.asList(productsWriteRequest));
        writeRequestMap.put("Orders", Arrays.asList(orderWriteRequest));

        BatchWriteItemRequest batchWriteItemRequest = BatchWriteItemRequest.builder().requestItems(writeRequestMap).build();

        BatchWriteItemResponse batchWriteItemResponse = dynamoDbClient.batchWriteItem(batchWriteItemRequest);

        // Implement a retry mechanism for batchWriteItem operations that encounter errors.
        while (!batchWriteItemResponse.unprocessedItems().isEmpty()) {
            Map<String, List<WriteRequest>> unprocessedItems = batchWriteItemResponse.unprocessedItems();
            batchWriteItemRequest
                    = BatchWriteItemRequest.builder().requestItems(unprocessedItems).build();
            batchWriteItemResponse = dynamoDbClient.batchWriteItem(batchWriteItemRequest);
        }
    }
}

Understanding BatchWriteItemRequest

The batchWriteItem() method in the DynamoDBClient allows you to perform multiple write operations (puts or deletes) across one or more tables in a single request. You provide a BatchWriteItemRequest object to specify the items and actions to be performed.


The requestItems() method in a BatchWriteItemRequest class defines the data to be written to DynamoDB. It takes a map where each key is a DynamoDB table name and the corresponding value is a list of WriteRequest operations (put or delete) to be performed on that table.


Handling Unprocessed Items: Retrying BatchWriteItem Operations

unprocessedItems() is a response parameter returned by the DynamoDB BatchWriteItemRequest operation. It contains a list of items that couldn't be processed due to reasons like exceeding provisioned throughput or internal processing errors.


Essentially, it's a mechanism for handling failed write operations. You can retry these unprocessed items in subsequent BatchWriteItemRequest until all items are successfully written to DynamoDB.

If the requested data exceeds these limits, or if there's insufficient table capacity, or an internal error occurs, the operation might return only a portion of the results. In such cases, the system provides information about the UnprocessedKeys, allowing you to retry the operation to retrieve the remaining data.(alert-passed)
When DynamoDB returns unprocessed items in a batch operation, it's essential to retry these items. However, to avoid overwhelming the system and increasing the likelihood of success, implement an exponential backoff strategy. This means progressively increasing the delay between retries. By doing so, you reduce the chance of encountering throttling issues and improve the overall reliability of your batch operations.(alert-error)

Understanding WriteRequest: Building Blocks for Batch Write Operations

A WriteRequest is a container for specifying either a PutItem or DeleteItem operation within a BatchWriteItem request.


You can only perform one of these operations (Put or Delete) per WriteRequest. If you need to perform both, you'll need separate WriteRequest objects. Each WriteRequest contains either a PutRequest or a DeleteRequest object.


PutRequest: Inserting or Updating Items

If you want to insert or update an item, you use a PutRequest object within your WriteRequest. A PutRequest contains an Item method, which is a map representing the item to be put into the table.


DeleteRequest: Removing Items from DynamoDB

If you want to delete an item, you use a DeleteRequest object within your WriteRequest. A DeleteRequest contains a Key method, which is a map representing the primary key of the item to be deleted.


DynamoDB BatchGetItems: Efficiently Retrieve Multiple Items


You can use the BatchGetItem operation to fetch data from one or more tables. Specify the items you need by their primary keys, and the operation will return their corresponding attributes.


A single BatchGetItem operation can fetch up to 100 items with a maximum data size of 16 MB.


Java Program to Perform BatchGetItem Operations on DynamoDB

This Java program demonstrates how to efficiently fetch data from two DynamoDB tables, Orders and products, using the BatchGetItem operation. By specifying multiple items and their primary keys within a single request, we can optimize data retrieval performance compared to individual GetItem operations.


package in.learnjavaskills.springcloudawsdynamodb.service;

import org.springframework.stereotype.Service;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.*;

import java.time.LocalDate;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
public class BatchItemExample
{
    private final DynamoDbClient dynamoDbClient;

    public BatchItemExample(DynamoDbClient dynamoDbClient) {
        this.dynamoDbClient = dynamoDbClient;
    }
    
    public void batchGetItem() {

        Map<String, AttributeValue> productsKeys = new HashMap<>();
        productsKeys.put("product_id", AttributeValue.fromS("pd_12345"));
        productsKeys.put("product_name", AttributeValue.fromS("Laptop"));

        Map<String, AttributeValue> ordersKeys = new HashMap<>();
        ordersKeys.put("order_id", AttributeValue.fromS("od_12345"));
        ordersKeys.put("customer_id", AttributeValue.fromS("c_12345"));

        Map<String, KeysAndAttributes> requestItems = new HashMap<>();
        KeysAndAttributes productsKeysAndAttributes = KeysAndAttributes.builder().consistentRead(false)
                .keys(productsKeys).build();
        requestItems.put("products", productsKeysAndAttributes);

        KeysAndAttributes ordersKeysAndAttributes  = KeysAndAttributes.builder()
                .keys(ordersKeys)
                .build();
        requestItems.put("Orders", ordersKeysAndAttributes);


        BatchGetItemRequest batchGetItemRequest = BatchGetItemRequest.builder().requestItems(requestItems).build();
        BatchGetItemResponse batchGetItemResponse = dynamoDbClient.batchGetItem(batchGetItemRequest);
        Map<String, List<Map<String, AttributeValue>>> responses = batchGetItemResponse.responses();
        responses.forEach( (table, itemsList) -> {
            System.out.println("table name: " + table);
            itemsList.forEach( attributesAndValues -> {
                attributesAndValues.forEach( (key, value) -> {
                    System.out.println("attributes name : " + key + ", attributes value: " + value.s());
                });
            });
        } );

        // Implement a retry mechanism for batchGetItem operations that encounter errors.
        while(!batchGetItemResponse.unprocessedKeys().isEmpty()) {
            Map<String, KeysAndAttributes> unprocessedKeys = batchGetItemResponse.unprocessedKeys();
            batchGetItemRequest = BatchGetItemRequest.builder().requestItems(unprocessedKeys).build();
            batchGetItemResponse = dynamoDbClient.batchGetItem(batchGetItemRequest);
            responses = batchGetItemResponse.responses();
            responses.forEach( (table, itemsList) -> {
                System.out.println("table name: " + table);
                itemsList.forEach( attributesAndValues -> {
                    attributesAndValues.forEach( (key, value) -> {
                        System.out.println("attributes name : " + key + ", attributes value: " + value.s());
                    });
                });
            } );
        }
    }
}

Understanding BatchGetItemRequest

The batchGetItem() method in the DynamoDBClient allows you to efficiently retrieve multiple items from one or more tables in a single operation. To specify the items you want to fetch, you create a BatchGetItemRequest object.


The requestItems() method within a BatchGetItemRequest specifies the tables and items to retrieve. It takes a map where the keys are table names, and the values are objects containing information about the items to fetch from that table, such as their primary keys and any projection expressions.


Conclusion


By effectively utilizing the BatchWriteItem and BatchGetItem operations, you can significantly enhance the efficiency and performance of your DynamoDB interactions. By understanding the core concepts, including WriteRequest, PutRequest, DeleteRequest, and handling unprocessed items, you're well-equipped to optimize your data manipulation strategies.


To learn more about DynamoDB transactions and how to use TransactWriteItems and TransactGetItems, check out my latest blog post on (getButton) #text=(DynamoDB Transactions with TransactWriteItems and TransactGetItems) #icon=(link) #color=(#35a576)

The complete code for this project is available on my GitHub repository (getButton) #text=(GitHub) #icon=(share) #color=(#000000)

Keep learning and keep growing.

Post a Comment

0 Comments
Post a Comment (0)

#buttons=(Accept !) #days=(20)

Our website uses cookies to enhance your experience. Learn More
Accept !
To Top