如何在非主键属性上使用DynamoDB条件putItem来保证唯一性?

时间:2017-04-06 22:02:07

标签: amazon-dynamodb

我正在为我们的某个产品实现一个名为默认命名的功能,我想看看条件putItem如何帮助我实现业务逻辑需求。

问题在于:

我们有一个传统的dynamoDB表,用于存储一些实体信息。架构是:entityId,name,manufacturer

entityId是主键,它实际上是一个UUID,名称和制造商只是属性。

现在,当我们向表中插入新条目时,我们的功能需要生成默认名称。每个制造商的默认名称必须是唯一的,我们希望使用序号来表示它。

E.g。在表格中我们有2个现有项目

123,  lucy, apple
3672, tom, apple

现在,如果我想在表格中插入另一个制造商apple条目,我需要生成“third”作为名称属性

5678, third, apple

看起来很简单,我只需要对apple的所有实体进行读取并获取计数,然后使用count + 1作为name属性的默认值。

然而,我们的系统是分布式的,可能会有多个请求进入,并且可能发生竞争条件。如果我不做任何预防。两个请求可以在表中插入两个条目

5678, third, apple
9374, third, apple

相反,我们实际上希望他们成为

5678, third, apple
9374, forth, apple

5678, forth, apple
9374, third, apple

要解决这个问题我正在考虑将putItem与ConditionalExpression一起使用。对于上面的示例,首先执行读取,得到计数2,然后如果两个并发请求尝试插入

“5678,第三,苹果”和“9374,第三,苹果”进入表格,然后其中一个应该得到一个例外,我们可以再次增加计数并重试。

代码将是

try {
    Expected expect = new Expected("name").notExist();
    PutItemSpec putItemSpec = new PutItemSpec().withItem(item).withExpected(expected);
   entityTable.putItem(putItemSpec);
} catch (ConditionalExpression ex) {
   .. increment count and do retry
}

但是我发现不起作用,没有异常抛出。我是否误解了有条件的提出?我怎样才能实现目标?

1 个答案:

答案 0 :(得分:1)

ConditionExpression不能用于此目的。对于来自RDBMS领域的人来说,ConditionExpression在DynamoDB中可能会产生误导。不应将其视为RDBMS表约束检查。

说明

PutItem UpdateItem DeleteItem 操作上指定了

ConditionExpression。这些操作对表定义的唯一键进行操作,该键可以只是哈希键或哈希+排序键。

因此,运行这些操作时,唯一键标识表中的唯一项。情况可能如下

  • PutItem-另一个具有相同唯一键的项目已经存在
  • UpdateItem-找到要更新的项目
  • DeleteItem-找到要删除的项目

ConditionExpression只需对该选定项进行操作以执行条件检查。因此,它不能用于检查同一表中其他项目的条件,也不能用于检查其他非关键属性之间的唯一性。

参考:https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.ConditionExpressions.html

推荐

为适当地处理这种情况,应检查表的关键设计。参见https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/best-practices.html