DynamoDB自动附加到多个列表

时间:2018-11-21 17:48:09

标签: java amazon-dynamodb atomic

我有一条包含两个列表的记录。 多个服务同时添加到这些列表,每个服务恰好更新了其中一个列表。

这是我用于创建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是完全锁定记录,还是仅锁定当前更新的字段?

1 个答案:

答案 0 :(得分:1)

单个项目的更新是原子性的,因此,如果您使用ReturnValues.ALL_NEW,则可以看到该项目的完整状态,并且如果列表相等,则不会错过它。 (请参阅update文档。)

即使您看到列表何时相等,也可能在您能够对它们相等时做出反应,列表不再相等。如果您想确保列表保持相等,直到您可以做出反应,那么您将需要一个条件表达式来防止进一步的更新或分布式锁定解决方案。

编辑(2018-11-22)

没有文档直接说明对项目的更新是原子性的,但是我们可以推断单个项目中的所有属性都是原子性的。

让我们从以下假设开始:

  1. 如果条件为真,则conditional write完全成功。
  2. 如果条件为假,则拒绝有条件写入。
  3. 条件写可以用于 Optimistic Locking with Version Number
  4. 写操作不会自动更新所有属性。

假设我们有一个属性为hashkeyversiondata的物品。让我们说hashkey=123data = "Foo"version = 1

还假设有几乎同时出现的两个请求(请求A和请求B)都使用乐观锁定,并且都在尝试为data设置新值。

这是可能的事件顺序

  • 请求A –检查条件version==1
  • 请求B –检查条件version==1
  • 请求A – data = "Bar"
  • 请求B – data = "Bag"
  • 请求A – version=version+1
  • 请求B – 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")

如果不是自动更新所有属性,则可能是一系列事件:

  • 请求A –检查条件version==1 AND data=="Foo"
  • 请求A – version = version+1
  • 请求A –`data =“ Foo”
  • 请求B –检查条件canEdit==true
  • 请求B – version = version+1
  • 请求B – canEdit = true
  • 请求A – canEdit = false
  • 请求B – data = "Bar"

在两种情况下,初次求值时条件均为true,在两种情况下,该请求写入的内容均被另一个请求覆盖。 DynamoDB不允许这两个条件更新都成功,因此DynamoDB必须原子更新项目中的所有属性,因为这是确保A或B都将因ConditionCheckException而失败的唯一方法。

如果我的推理是正确的,则为了使1-3为真,必须为4为假,并且单个项目中的所有属性都将自动更新。