读取/更新操作上的Dynamodb ConditionalCheckFailedException - java sdk

时间:2014-10-23 16:50:20

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

我是DynamoDB的新手,并尝试使用事务支持的示例场景。我正在使用 dynamodb-transaction 库中提供的相同实体。唯一的区别是我用散列键添加了一个范围键。这是表格定义:

  • ItemId - >哈希键,字符串
  • ItemName - >范围键,字符串

@DynamoDBTable(tableName = "Item")
public static class ExampleItem {
    private String itemId;
    private String value;
    private String itemName;
    private Long version;
    @DynamoDBHashKey(attributeName = "ItemId")
    public String getItemId() {
        return itemId;
    }
    public void setItemId(String itemId) {
        this.itemId = itemId;
    }
    @DynamoDBRangeKey(attributeName="ItemName")
    public String getItemName() {
        return itemName;
    }
    public void setItemName(String itemName) {
        this.itemName = itemName;
    }
    public String getValue() {
        return value;
    }
    public void setValue(String value) {
        this.value = value;
    }
    @DynamoDBVersionAttribute
    public Long getVersion() {
        return version;
    }
    public void setVersion(Long version) {
        this.version = version;
    }
}

如您所见,我也在使用version属性。 现在,我正在尝试使用transaction / dbmapper执行简单的创建或更新方案。这是代码段。

Transaction t1 = txManager.newTransaction();
ExampleItem keyItem = new ExampleItem();
keyItem.setItemId("Item1");
keyItem.setItemName("USA");
ExampleItem item = t1.load(keyItem);
if (item != null) {
    item.setValue("Magenta");
    item.setItemName("UK");
    t1.save(item);
} else {
    item = new ExampleItem();
    item.setItemId(keyItem.getItemId());
    item.setItemName("USA");
    item.setValue("Violet");
    t1.save(item);
}
t1.commit();
t1.delete();

我能够毫无问题地添加记录,但是当我尝试读取记录并更新任何属性时,我遇到了问题。我遇到以下异常:

Uncaught exception:com.amazonaws.services.dynamodbv2.model.ConditionalCheckFailedException: Status Code: 0, AWS Service: null, AWS Request ID: null, AWS Error Code: null, AWS Error Message: Item {ItemId={S: Item1,}, ItemName={S: UK,}} had unexpected attributes: Status Code: 0, AWS Service: null, AWS Request ID: null, AWS Error Code: null, AWS Error Message: expected attribute(s) {version={Value: {N: 1,},Exists: true}} but found null
com.amazonaws.services.dynamodbv2.model.ConditionalCheckFailedException: Status Code: 0, AWS Service: null, AWS Request ID: null, AWS Error Code: null, AWS Error Message: Item {ItemId={S: Item1,}, ItemName={S: UK,}} had unexpected attributes: Status Code: 0, AWS Service: null, AWS Request ID: null, AWS Error Code: null, AWS Error Message: expected attribute(s) {version={Value: {N: 1,},Exists: true}} but found null

看起来它与版本有关,但不确定我哪里出错了。任何指针都将受到赞赏。

-Thanks

Shamik

3 个答案:

答案 0 :(得分:3)

在创建项目类时,您需要设置版本。它期待1,但发现null。 versionedAttribute期望一个值,并且似乎第一次创建项目时它会期望为1.

如果您以后更新此项,则应注意在内部增加版本。

答案 1 :(得分:2)

Dynamodb具有Optimistic Locking的概念,是确保您正在更新(或删除)的客户端项目与DynamoDB中的项目相同的策略。

  1. 首先保存:
  2. 如果是第一次更新,则必须遵循此格式

    // Step1: Do a GET
    ExampleItem itemInDynamo = dynamoDBMapper.load(ExampleItem.class, "item_id_value", "item_name_value");
    // Step2: Get the version in Dynamo
    Long versionInDynamo = itemInDynamo.getVersion();
    DynamodbSaveExpression saveExpression = 
           new DynamodbSaveExpression()
           .withExpectedEntry("version", 
           new ExpectedAttributeValue(new AttributeValue().withN(versionInDynamodb.toString())));
    // Step3: Update the item
    dynamodbmapper.save(itemToSave, saveExpression);
    

    说明:我们告诉 itemToSave 只有在" ItemId"," ItemValue"在dynamodb中没有组合。

    1. 更新为现有项目:
    2. 要更新dynamodb中的现有项目,您必须遵循此格式

      aws --region ap-northeast-1 ec2 describe-images \
          --owners 591542846629 | \
          jq '.Images[] | {Name, ImageId} | select(.Name | contains("amazon-ecs-optimized") )' | \
          jq -s 'sort_by(.Name) | reverse | .[0].ImageId' -r
      

      只有在您保存的版本在Dynamodb中保存相同时,保存才会成功,如果不保存,则ConditionalCheckFailedException将失败,然后您从步骤1重试。这是先读然后写。

答案 2 :(得分:0)

通常,当您的对于dynamodb中的多个元素相同时会发生这种情况。例如,如果你有文件夹,其id为hashKey,folderName为rangeKey,则不会再次哈希(hashkey + rangeKey)保存文件夹会是一样的。