我正在为我们的某个产品实现一个名为默认命名的功能,我想看看条件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
}
但是我发现不起作用,没有异常抛出。我是否误解了有条件的提出?我怎样才能实现目标?
答案 0 :(得分:1)
ConditionExpression不能用于此目的。对于来自RDBMS领域的人来说,ConditionExpression在DynamoDB中可能会产生误导。不应将其视为RDBMS表约束检查。
说明
在 PutItem , UpdateItem 和 DeleteItem 操作上指定了ConditionExpression。这些操作对表定义的唯一键进行操作,该键可以只是哈希键或哈希+排序键。
因此,运行这些操作时,唯一键标识表中的唯一项。情况可能如下
ConditionExpression只需对该选定项进行操作以执行条件检查。因此,它不能用于检查同一表中其他项目的条件,也不能用于检查其他非关键属性之间的唯一性。
推荐
为适当地处理这种情况,应检查表的关键设计。参见https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/best-practices.html