Dynamodb ConditionalCheckFailedException on read / update operation
I'm new to DynamoDB and trying out a sample scenario using Transaction support. I'm using the same entity provided in dynamodb-transaction library. Only difference is I've added a range key with the hash key. Here's the table definition:
ItemId
--> hash key , string ItemName
--> range key, string @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;
}
}
As you can see, I'm using the version attribute as well. Now, I'm trying to execute a simple create or update scenario using transaction/dbmapper. Here's the code snippet.
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();
I'm able to add the record without any issue, but I'm having a problem when I'm trying to read the record and update any attribute. I'm getting the following exception:
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
Looks like it has something to do with version, but not sure where am I going wrong. Any pointers will be appreciated.
-Thanks
Shamik
Looks like you need to set the version when creating the item class. It's expecting 1 but found null. The versionedAttribute is expecting a value, and it seems when the item is created for the first time it will expect 1.
If you update this item in the future, it should take care of incrementing the version internally.
Dynamodb has this concept of Optimistic Locking, is strategy to ensure that the client-side item that you are updating (or deleting) is the same as the item in DynamoDB.
If it's a first update, you have to follow this format
DynamodbSaveExpression saveExpression =
new DynamodbSaveExpression()
.withExpectedEntry("ItemId", new ExpectedAttributeValue().withExists(false)
.withConditionalOperator(AND)
.withExpectedEntry("ItemName", new ExpectedAttributeValue().withExists(false));
// saving the item to dynamodb
dynamodbmapper.save(itemToSave, saveExpression);
Explanation: We are telling that itemToSave should be saved only when both "ItemId", "ItemValue" combination is not there in dynamodb.
For an update to an existing item in dynamodb, you have to follow this format
// 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);
Save will only succeed if the version with which you are saving is the same in the Dynamodb, if not save will fail with ConditionalCheckFailedException then you have retry from step1. This is Read first then Write.
Usualy this occurs when your keys are same for more then one element in dynamodb. For example if you have Folder with id as hashKey and folderName as rangeKey, You wont save the Folder again where your hash (hashkey+rangeKey) would be same.
链接地址: http://www.djcxy.com/p/82222.html上一篇: 某些用户的电子邮件为空