我有一条包含两个列表的记录。 多个服务同时添加到这些列表,每个服务恰好更新了其中一个列表。
这是我用于创建UpdateItemSpec
private UpdateItemSpec updateList1(List<String> values) {
return new UpdateItemSpec()
.withPrimaryKey("recordKey", "key")
.withUpdateExpression("SET list1 = list_append(if_not_exists(list1, :initialVal), :val)")
.withValueMap(new ValueMap().withList(":val", values)
.withList(":initialVal", new ArrayList<>()))
.withReturnValues(ReturnValue.ALL_NEW);
}
private UpdateItemSpec updateList2(List<String> values) {
return new UpdateItemSpec()
.withPrimaryKey("recordKey", "key")
.withUpdateExpression("SET list2 = list_append(if_not_exists(list2, :initialVal), :val)")
.withValueMap(new ValueMap().withList(":val", values)
.withList(":initialVal", new ArrayList<>()))
.withReturnValues(ReturnValue.ALL_NEW);
}
鉴于更新应该使我进入列表相等的状态(我不知道需要多少次迭代),我的目标是检查每个update
之后列表是否相等(使用从update
返回的项目)。我需要做些什么来确保updates
在记录中是原子的,并且我不会错过列表相等的迭代吗?
换句话说,update
是完全锁定记录,还是仅锁定当前更新的字段?
答案 0 :(得分:1)
单个项目的更新是原子性的,因此,如果您使用ReturnValues.ALL_NEW
,则可以看到该项目的完整状态,并且如果列表相等,则不会错过它。 (请参阅update文档。)
即使您看到列表何时相等,也可能在您能够对它们相等时做出反应,列表不再相等。如果您想确保列表保持相等,直到您可以做出反应,那么您将需要一个条件表达式来防止进一步的更新或分布式锁定解决方案。
编辑(2018-11-22)
没有文档直接说明对项目的更新是原子性的,但是我们可以推断单个项目中的所有属性都是原子性的。
让我们从以下假设开始:
假设我们有一个属性为hashkey
,version
和data
的物品。让我们说hashkey=123
,data = "Foo"
和version = 1
。
还假设有几乎同时出现的两个请求(请求A和请求B)都使用乐观锁定,并且都在尝试为data
设置新值。
这是可能的事件顺序
version==1
version==1
data = "Bar"
data = "Bag"
version=version+1
version=version+1
该商品的最终状态是
hashkey=123
version=3
data="Bag"
由于乐观锁定,不应发生此状态。
如果使用此策略,则可以保护数据库写操作免受他人写操作的覆盖,反之亦然。
现在,您可能会反对所有这一切,这表明版本增量在条件评估中自动发生。但是,您还应该记住,条件表达式可以在任意数量的属性上具有任意数量的条件,因此条件表达式中提到的所有属性都必须与条件表达式评估一起进行原子更新。
但是,这仅表明至少必须对某些属性进行原子更新,而并非全部都是。好吧,这里有两种可能的实现。 (1)DynamoDB确定条件表达式中存在哪些属性(从0到所有属性),并仅原子更新这些属性。 (2)DynamoDB自动更新项目的所有属性。但请考虑以下示例,其中ConditionExpression中没有的属性会影响更新的正确性。
假设我们的商品还有1个属性:canEdit
,最初是正确的。这次,请求A设置canEdit=false
,请求B设置values = list_append(values, "Bar")
。
如果不是自动更新所有属性,则可能是一系列事件:
version==1 AND data=="Foo"
version = version+1
canEdit==true
version = version+1
canEdit = true
canEdit = false
data = "Bar"
在两种情况下,初次求值时条件均为true,在两种情况下,该请求写入的内容均被另一个请求覆盖。 DynamoDB不允许这两个条件更新都成功,因此DynamoDB必须原子更新项目中的所有属性,因为这是确保A或B都将因ConditionCheckException而失败的唯一方法。
如果我的推理是正确的,则为了使1-3为真,必须为4为假,并且单个项目中的所有属性都将自动更新。