使用DynamoDB乐观锁定的正确方法

时间:2016-02-27 17:06:42

标签: java amazon-web-services amazon-dynamodb

我试图了解DynamoDB乐观锁定对我的用例是否正确,还是应该做其他事情。

我试图在我的Java方法中执行以下操作。

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

我想根据某些条件成功更新相同的项目。我已经创建了一个版本属性,因此乐观锁定可以正常工作,当我有多个请求进入时,只有一个请求获取并更新数据。

我试图理解以下内容:

  1. 当其他某个线程尝试更新该值但版本ID已更改时会发生什么情况,我无法找到有关将抛出异常的任何文档?

  2. 我应该使用同步功能吗?考虑到多个请求将会进入?但是,对我而言,这似乎违背了乐观锁定的目的,因为我并不关心哪个请求首先获得访问权。

  3. 这个问题有替代解决方案吗?

  4. 我已通过以下文档: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBMapper.OptimisticLocking.html

3 个答案:

答案 0 :(得分:4)

  
      
  1. 当其他一些线程尝试更新值时会发生什么   版本ID已更改,我找不到任何关于什么的文档   异常将被抛出?
  2.   

如果版本ID发生了变化,它似乎会抛出ConditionalCheckFailedException。

  
      
  1. 我应该使用同步功能吗?考虑到   多个请求将进来?但是,对我而言,这似乎就是这样   打败乐观锁定的目的,因为我不关心哪个   请求首先访问。
  2.   

你是对的,使用同步函数会破坏乐观锁定的目的。你不需要两者。并且乐观锁定在分布式环境中工作,其中可能不会由相同的服务器生成更新。

  
      
  1. 这个问题有替代解决方案吗?
  2.   

您可以使用低级DynamoDB API和条件更新。我认为这就是乐观锁定在底下使用的东西。如果您使用的是Java或.Net以外的语言,则必须使用低级API。由于您使用的是Java并且已经使用了高级API,因此我会坚持使用它。

答案 1 :(得分:1)

乐观锁定现已正式支持:

AWS Documentation

您需要在字段中添加@ DynamoDBVersionAttribute 。如果您需要更复杂的数据锁,请考虑使用Conditional Constraints,它们可以锁定数据并防止不必要的修改

答案 2 :(得分:0)

如果您需要保证应用所有多个请求(来自不同的线程/服务器),您可以使用以下乐观锁定实现:

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...");
        }
    }
}

如果item已经被另一个请求更新了,我们将收到ConditionalCheckFailedException并再次尝试,直到应用更改。

ConditionalCheckFailedException - 当预期值与系统(数据库)中找到的值不匹配时,抛出此异常。抛出此异常:

  • 如果您对@DynamoDBVersionAttribute使用乐观锁定,并且服务器上的版本值与客户端上的值不同;
  • 如果使用带有DynamoDBSaveExpression / DynamoDBDeleteExpression的dynamoDBMapper保存/删除数据时指定自己的条件约束,则这些约束失败。

关于@Nawaz问题,如果您尚未指定自己的条件约束(使用DynamoDBSaveExpression和DynamoDBDeleteExpression),则此异常是由于版本更改引起的。如果捕获ConditionalCheckFailedException,您将获得以下信息:

requestId = …
errorCode = ConditionalCheckFailedException
errorType = {AmazonServiceException$ErrorType} "Client"
errorMessage = The conditional request failed
statusCode = 400
serviceName = AmazonDynamoDBv2