Correct way to use DynamoDB Optimistic Locking

2020-07-11 05:39发布

I'm trying to understand if DynamoDB Optimistic Locking is the correct thing for my use case or should I be doing something else.

I'm trying to do the following in my Java method.

function updateItem(String key) {
    Item item = mapper.load(Item.class, key);
    if (some condition) {
        item.setValue(item.getValue() + 1);
        mapper.save(item);
    }
 }

I want to update the same item based on some condition succeeding. I've created a version attribute, so that Optimistic locking works and when I have multiple requests coming in, only one request gets and updates the data.

I'm trying to understand the following:

  1. What happens when some other thread tries to update the value but the version id has changed, I couldn't find any documentation on what exception will be thrown?

  2. Should I be using a synchronized function for this? Considering multiple requests will be coming in? But, to me this seems like it defeats the purpose of optimistic locking, since I don't care which request gets access first.

  3. Is there an alternate solution to this problem?

I've been through the following documentation: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBMapper.OptimisticLocking.html

2条回答
啃猪蹄的小仙女
2楼-- · 2020-07-11 06:03

If you need to guarantee that all multiple requests (from different threads / servers) were applied, you could use the following implementation of optimistic locking:

public void updateItem(String key) {
    while (true) {
        try {
            Item item = dynamoDBMapper.load(Item.class, key);
            if (some condition) {
                item.setValue(item.getValue() + 1);
                dynamoDBMapper.save(item);
            }
            break;
        } catch (ConditionalCheckFailedException e) {
            System.out.println("ConditionalCheckFailedException. Retrying again...");
        }
    }
}

Here if item has already been updated by another request, we will receive ConditionalCheckFailedException and trying one more time until changes will be applied.

ConditionalCheckFailedException - this exception is thrown when an expected value does not match what was found in the system (database). This exception will be thrown:

  • if you use optimistic locking with @DynamoDBVersionAttribute, and version value on the server is different from value on the client side;
  • if you specify your own conditional constraints while saving / deleting data using dynamoDBMapper with DynamoDBSaveExpression / DynamoDBDeleteExpression and these constraints are failed.

Regarding @Nawaz question, if you haven’t specified your own conditional constraints (using DynamoDBSaveExpression and DynamoDBDeleteExpression), this exception is due to changed version. If you catch ConditionalCheckFailedException, you will have the following information:

requestId = …
errorCode = ConditionalCheckFailedException
errorType = {AmazonServiceException$ErrorType} "Client"
errorMessage = The conditional request failed
statusCode = 400
serviceName = AmazonDynamoDBv2
查看更多
▲ chillily
3楼-- · 2020-07-11 06:16
  1. What happens when some other thread tries to update the value but the version id has changed, I couldn't find any documentation on what exception will be thrown?

It appears to throw a ConditionalCheckFailedException if the version ID has changed.

  1. Should I be using a synchronized function for this? Considering multiple requests will be coming in? But, to me this seems like it defeats the purpose of optimistic locking, since I don't care which request gets access first.

You are correct, using a synchronized function would defeat the purpose of optimistic locking. You don't need both. And optimistic locking works in a distributed environment where updates may not be generated by the same servers.

  1. Is there an alternate solution to this problem?

You could use the low-level DynamoDB API and Conditional Updates. I think that's what the Optimistic Locking is using underneath. If you were using a language other than Java or .Net you would have to use the low-level API. Since you are using Java and already working with the high-level API I would stick with that.

查看更多
登录 后发表回答