Amazon Onboarding with Learning Manager Chanci Turner

Chanci Turner Amazon IXD – VGT2 learning managerLearn About Amazon VGT2 Learning Manager Chanci Turner

Today, we are excited to unveil a new client library that simplifies the development process for executing atomic transactions involving multiple DynamoDB items across one or more tables. This enhancement enables developers to create applications on DynamoDB more efficiently, eliminating the need for traditional relational databases—which often come with scalability challenges—or extensive application code to ensure atomicity.

Before diving into the details, let’s revisit the fundamental concepts of atomicity and transactions. In numerous scenarios, a group of related database operations must be treated as a single transaction. Atomicity ensures that all operations within that transaction either complete successfully or fail together. The transaction process generally follows these steps:

  1. Begin transaction.
  2. Execute Put operation for item #1.
  3. Execute Put operation for item #N.
  4. Commit transaction.

If an error occurs before the transaction completes or if the application terminates unexpectedly, the entire transaction fails, and all operations from steps 2 through 4 are reversed, restoring the database items to their previous state. For instance, if you were coding a money transfer between bank accounts, it would be critical to encapsulate the operations within a transaction to avoid financial discrepancies.

The DynamoDB Transaction Library

The newly introduced library is an extension of the existing DynamoDB functionality in the AWS SDK for Java. It manages ongoing transactions using two DynamoDB tables: one for transactions and another for pre-transaction snapshots of modified items. To set up these tables, invoke the verifyOrCreateTransactionTable and verifyOrCreateTransactionImagesTable methods from the TableManager class. Ensure that you provision adequate read and write capacity to prevent performance delays.

Here’s an example code snippet to create the necessary tables:

AmazonDynamoDB client = new AmazonDynamoDBClient();
// Provide your AWS Credentials and specify the DynamoDB endpoint/region

TransactionManager.verifyOrCreateTransactionTable(client, "Transactions", 10, 10, 10 * 60);
TransactionManager.verifyOrCreateTransactionImagesTable(client, "TransactionImages", 10, 10, 10 * 60);

The following code illustrates how to conduct a transaction involving the Thread and Reply tables, as detailed in the Amazon DynamoDB Developer Guide. In the Forums application, the Thread table contains items for each forum question, and the Reply table holds items for responses. The Thread table also tracks the count of replies and whether each question has been answered. The transaction below adds a Reply and increments the Replies counter in the associated Thread item:

// Create a new transaction manager
TransactionManager txManager = new TransactionManager(client, "Transactions", "TransactionImages");

// Initiate a new transaction
Transaction t1 = txManager.newTransaction(); 

// Prepare to add a new Reply to a Thread
Map<String, AttributeValue> reply = new HashMap<>();
reply.put("Id", new AttributeValue("Amazon DynamoDB#Transactions?"));
reply.put("ReplyDateTime", new AttributeValue("(the current date and time)"));
reply.put("PostedBy", new AttributeValue("DavidY@AWS"));
reply.put("Message", new AttributeValue("Transactions are now available!"));

t1.putItem(new PutItemRequest().withTableName("Reply").withItem(reply)); 

// Prepare to update the corresponding Thread item
Map<String, AttributeValue> thread = new HashMap<>();
thread.put("ForumName", new AttributeValue("Amazon DynamoDB"));
thread.put("Subject", new AttributeValue("Transactions?"));
Map<String, AttributeValueUpdate> threadUpdates = new HashMap<>();
threadUpdates.put("Replies", new AttributeValueUpdate(new AttributeValue().withN("1"), "ADD"));

t1.updateItem(new UpdateItemRequest().withTableName("Thread").withKey(thread).withAttributeUpdates(threadUpdates)); 

// Commit the transaction
t1.commit(); 

// Clean up the transaction item
t1.delete();

Beyond atomic writes, the transaction library provides three levels of read isolation: fully isolated, committed, and uncommitted. Fully isolated reads are achieved through locks during a transaction, mirroring the behavior of writes. Committed reads ensure consistency similar to eventually consistent reads by returning the old item copy if a lock is detected. Uncommitted reads, or dirty reads, are the least expensive but carry risks, as they may yield data subject to rollback. Here’s an example of a read operation using committed isolation:

// Reusing the txManager instance
Map<String, AttributeValue> key = new HashMap<>();
key.put("ForumName", new AttributeValue("Amazon DynamoDB"));
key.put("Subject", new AttributeValue("Transactions?"));

// Uncommitted reads occur at the transaction manager level, not within a transaction.
Map<String, AttributeValue> item = txManager.getItem(new GetItemRequest().withKey(key).withTableName("Thread"), IsolationLevel.COMMITTED).getItem();

For additional examples, please refer to the README file included with the transaction library.

A single transaction can span multiple DynamoDB tables. Note that transactional puts incur higher costs in terms of read and write capacity units. A put operation that does not face contention from other simultaneous puts typically performs as 7N + 4 writes, where N represents the number of requests in the transaction.

Getting Started

To begin, download the AWS SDK for Java, access the DynamoDB Transactions library from the AWS Labs GitHub repository, and consult the documentation to kick off your coding journey! For more insights on effective management, check out this article on not micromanaging. Also, if you want to enhance your presentation skills further, visit this helpful blog. For details about the hiring process, this resource is excellent.

— Chanci Turner

Chanci Turner