How will you ensure that no two threads update the same db record in parallel in amazon DynamoDB

Upasana | April 24, 2019 | 3 min read | 3,228 views


There are two ways to ensure that lost updates phenomenon does not happen in DynamoDB tables:

  1. using Conditional Writes in DyanmoDB

  2. using Optimistic Locking using @Version support

We will discuss both the approaches one by one.

Let’s create a fictional scenario, where we have a e-commerce product in our database table with the below definition:

Product Model
@DynamoDBTable(tableName = "local-product")
public class Product {
    @DynamoDBHashKey(attributeName = "id")  (1)
    private String id;

    @DynamoDBAttribute
    private String name;

    @DynamoDBAttribute
    private long price;

    @DynamoDBVersionAttribute      (2)
    private long version;
1 id is the hashkey for entity
2 version field is used for maintaining the consistency

Hashkey for this domain model is id of the product.

Conditional Writes in DynamoDB

DynamoDB provides mechanism to execute conditional writes, where db record is updated only if certain condition is met, otherwise changes are discarded and update fails with an ConditionalCheckFailedException.

ProductDao definition
@Repository
public class ProductDao {

    @Autowired
    private AmazonDynamoDBClient dynamoDBClient;

    @Autowired
    private DynamoDB dynamoDB;

    public void incrementPrice(String productId, long newPrice, long existingPrice) {
        Map<String, AttributeValue> key = new HashMap<>();
        key.put("id", new AttributeValue().withS(productId));
        UpdateItemRequest updateRequest =
                new UpdateItemRequest().withTableName("local-content")
                        .withKey(key)
                        .addAttributeUpdatesEntry("price", new AttributeValueUpdate()
                                .withValue(new AttributeValue().withN("" + newPrice))
                                .withAction(AttributeAction.ADD))
                        .addExpectedEntry("price", new ExpectedAttributeValue(new AttributeValue().withN("" + existingPrice)));
        dynamoDBClient.updateItem(updateRequest);
    }
}

incrementPrice() method will atomically update the price of a product to new price only if existing price of product matches the given price.

Optimistic Locking using @Version support

Optimistic locking is a strategy to ensure that the client-side item that you are updating (or deleting) is the same as the item in DynamoDB. If you use this strategy, then your database writes are protected from being overwritten by the writes of others — and vice-versa.

With optimistic locking, each item has an attribute that acts as a version number. If you retrieve an item from a table, the application records the version number of that item. You can update the item, but only if the version number on the server side has not changed. If there is a version mismatch, it means that someone else has modified the item before you did; the update attempt fails, because you have a stale version of the item. If this happens, you simply try again by retrieving the item and then attempting to update it. Optimistic locking prevents you from accidentally overwriting changes that were made by others; it also prevents others from accidentally overwriting your changes.

We can add an additional field to Product domain model for version attribute and annotate it with @DynamoDBVersionAttribute. Once this field is added to the domain model, DynamoDB will make sure that parallel updates to the single record fail with an exception ConditionalCheckFailedException. Thus the lost updates phenomenon will not occur.

Product Dao
public Product get(String productId) {
    DynamoDBMapper mapper = new DynamoDBMapper(dynamoDBClient);
    Product dbItem = mapper.load(Product.class, productId);
    return dbItem;
}

public Product update(String productId, long newPrice) {
    Product product = get(productId);
    product.setPrice(newPrice);
    final DynamoDBMapperConfig.Builder builder = new DynamoDBMapperConfig.Builder();
    builder.setConsistentReads(DynamoDBMapperConfig.ConsistentReads.EVENTUAL);
    builder.setSaveBehavior(DynamoDBMapperConfig.SaveBehavior.UPDATE_SKIP_NULL_ATTRIBUTES);
    DynamoDBMapperConfig mapperConfig = builder.build();
    DynamoDBMapper mapper = new DynamoDBMapper(dynamoDBClient, mapperConfig);
    mapper.save(product);
    return product;
}

The update() method will fail if some other thread in parallel tries to update the same DB record, since this version is automatically changed whenever an update happens.

ConditionalCheckFailedException is thrown if:
  • You use optimistic locking with @DynamoDBVersionAttribute and the version value on the server is different from the value on the client side.

  • You specify your own conditional constraints while saving data by using DynamoDBMapper with DynamoDBSaveExpression and these constraints failed.

Disabling Optimistic Locking

To disable optimistic locking, you can change the DynamoDBMapperConfig.SaveBehavior enumeration value from UPDATE to CLOBBER. You can do this by creating a DynamoDBMapperConfig instance that skips version checking and use this instance for all your requests.

Update without Optimistic Locking
 public Product updateWithoutOptimisticLocking(String productId, long newPrice) {
    DynamoDBMapper mapper = new DynamoDBMapper(dynamoDBClient);
    // Load a catalog item.
    Product item = mapper.load(Product.class, productId);
    item.setPrice(newPrice);
    // Save the item.
    mapper.save(item, new DynamoDBMapperConfig(DynamoDBMapperConfig.SaveBehavior.CLOBBER));
    return item;
}

Download source code

You can download source code for this repository hosted at Github:


Top articles in this category:
  1. Scan all records of a Amazon DynamoDB table using a Java Code
  2. How to implement Atomic Counters in DynamoDB for high throughput
  3. AWS DynamoDB Java interview questions
  4. How to automatically Retry DynamoDB Write on ProvisionedThroughputExceededException
  5. What are different types of NoSql databases in general?
  6. What are Best Practices for Using Amazon DynamoDB?
  7. What are Conditional Writes in AWS DynamoDB

Recommended books for interview preparation:

Find more on this topic: