我试图了解DynamoDB乐观锁定对我的用例是否正确,还是应该做其他事情。
我试图在我的Java方法中执行以下操作。
function updateItem(String key) {
Item item = mapper.load(Item.class, key);
if (some condition) {
item.setValue(item.getValue() + 1);
mapper.save(item);
}
}
我想根据某些条件成功更新相同的项目。我已经创建了一个版本属性,因此乐观锁定可以正常工作,当我有多个请求进入时,只有一个请求获取并更新数据。
我试图理解以下内容:
当其他某个线程尝试更新该值但版本ID已更改时会发生什么情况,我无法找到有关将抛出异常的任何文档?
我应该使用同步功能吗?考虑到多个请求将会进入?但是,对我而言,这似乎违背了乐观锁定的目的,因为我并不关心哪个请求首先获得访问权。
这个问题有替代解决方案吗?
答案 0 :(得分:4)
- 当其他一些线程尝试更新值时会发生什么 版本ID已更改,我找不到任何关于什么的文档 异常将被抛出?
醇>
如果版本ID发生了变化,它似乎会抛出ConditionalCheckFailedException。
- 我应该使用同步功能吗?考虑到 多个请求将进来?但是,对我而言,这似乎就是这样 打败乐观锁定的目的,因为我不关心哪个 请求首先访问。
醇>
你是对的,使用同步函数会破坏乐观锁定的目的。你不需要两者。并且乐观锁定在分布式环境中工作,其中可能不会由相同的服务器生成更新。
- 这个问题有替代解决方案吗?
醇>
您可以使用低级DynamoDB API和条件更新。我认为这就是乐观锁定在底下使用的东西。如果您使用的是Java或.Net以外的语言,则必须使用低级API。由于您使用的是Java并且已经使用了高级API,因此我会坚持使用它。
答案 1 :(得分:1)
乐观锁定现已正式支持:
您需要在字段中添加@ 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 - 当预期值与系统(数据库)中找到的值不匹配时,抛出此异常。抛出此异常:
关于@Nawaz问题,如果您尚未指定自己的条件约束(使用DynamoDBSaveExpression和DynamoDBDeleteExpression),则此异常是由于版本更改引起的。如果捕获ConditionalCheckFailedException,您将获得以下信息:
requestId = …
errorCode = ConditionalCheckFailedException
errorType = {AmazonServiceException$ErrorType} "Client"
errorMessage = The conditional request failed
statusCode = 400
serviceName = AmazonDynamoDBv2