DynamoDBMapper仅在唯一时保存项目

Chr*_*ner 7 java amazon-web-services amazon-dynamodb

我试图根据两个不同列的组合将表中的项保持唯一.

我有一个instanceId和imageId列(以及其他)并基于Stackoverflow和AWS论坛上的几个帖子,下面应该有效吗?

public void saveUnique(Server server) {
    DynamoDBSaveExpression saveExpression = new DynamoDBSaveExpression();
    Map<String, ExpectedAttributeValue> expectedAttributes =
        ImmutableMap.<String, ExpectedAttributeValue>builder()
            .put("instanceId", new ExpectedAttributeValue(false))
            .put("imageId", new ExpectedAttributeValue(false))
            .build();
    saveExpression.setExpected(expectedAttributes);
    saveExpression.setConditionalOperator(ConditionalOperator.AND);
    try {
        mapper.save(server, saveExpression);
    } catch (ConditionalCheckFailedException e) {
        //Handle conditional check
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,每次我尝试保存重复项(相同的instanceId和imageId)时,它都会成功保存到数据库中.

我在这里错过了什么?

EDIT RE notionquest回答

更新到下面的答案.

我有一个每分钟运行一次API的工作.API的响应表示为ServerPOJO.它Server有一个名为的属性instanceId.

我要确保,如果Server与instanceId已经在数据库中,不救它.

该Server对象的另一个属性id设置为表主键.

public void saveUnique(Server server) {
    DynamoDBSaveExpression saveExpression = new DynamoDBSaveExpression();

    Map<String, ExpectedAttributeValue> expected = new HashMap<>();
    expected.put("instanceId", new ExpectedAttributeValue(new AttributeValue(server.getInstanceId())).withComparisonOperator(ComparisonOperator.NE));
    saveExpression.setExpected(expected);

    try {
        mapper.save(server, saveExpression);
    } catch (ConditionalCheckFailedException e) {
        LOGGER.info("Skipped saving as not unique...");
    }
}
Run Code Online (Sandbox Code Playgroud)

此代码将一次又一次地保存Server对象,但不会抛出异常.

服务器POJO

@DynamoDBTable(tableName = "Servers")
public class Server {

    @Id
    private String id = UUID.randomUUID().toString();

    @DynamoDBTypeConvertedJson
    private Task task;

    @DynamoDBAttribute(attributeName = "instanceId")
    private String instanceId;

    public Server() {
    }

    @DynamoDBHashKey
    public String getId() {
        return id;
    }

    // other standard getters and setters
}
Run Code Online (Sandbox Code Playgroud)

xtx*_*xtx 5

2019年更新

在 2019 年,自提出问题以来,这里似乎没有任何变化。在 DynamoDB 中为非主键字段提供唯一性仍然很棘手。这是最近在亚马逊上发布的一篇文章:https : //aws.amazon.com/blogs/database/simulating-amazon-dynamodb-unique-constraints-using-transactions/

基本上,作者建议在同一个表中创建辅助记录,而不是使用如下所述的附加表。

例如,在下图中,为了确保instance_id=2c5d0cc8d900 是唯一值,您必须添加一个带有人工主键值“instance_id#2c5d0cc8d900”的记录。如果插入成功,则可以插入主记录本身。

+--------------------------+-------------------------+--------+----------------
|           id             |       instance_id       | attr1  | other fields... 
|                          |                         |        |
|      (primary key)       |     (a non-key field,   |        |
|                          |     must be unique)     |        |
+--------------------------+-------------------------+--------+----------------
| instance_id#2c5d0cc8d900 |                         |        |
| a9fd702a                 | 2c5d0cc8d900            | qwerty | ...
Run Code Online (Sandbox Code Playgroud)

虽然这种方法可能工作正常,但我个人仍然更喜欢使用一个单独的表格,如下面我的原始答案中所述。因为,当从包含此类辅助记录的表中读取数据时,您必须关心从实际记录中过滤它们。


原答案

如果我正确理解了这个问题,您希望确保不是哈希键的字段的唯一性。

(我不确定您为什么不将其instanceId用作 Servers 表的哈希键,我想您是有原因的)。

我的回答:看起来你不能不使用辅助表来做到这一点。

这是您现有的服务器表:

+----------------------------------------------+
|                 Servers                      |   
+----------------------------------------------+
| * id            the hash key                 |
| * instanceId    non-key field, must be unique|
|                                              |
| * ...                                        |
| * other fields                               |
| * ...                                        | 
+----------------------------------------------+
Run Code Online (Sandbox Code Playgroud)

我将创建一个以 instanceId 作为哈希键的附加表:

+----------------------------------------------+
|                 Instance                     |   
+----------------------------------------------+
| * instanceId    the hash key                 |
+----------------------------------------------+
Run Code Online (Sandbox Code Playgroud)

拥有这样一个表,在将记录保存到服务器之前,您必须首先通过将记录(putItem)添加到实例中来确保 instanceId 值是唯一的,并提供类似的 ConditionExpression attribute_not_exists(instanceId)。

并且只有当 put 操作完成且没有ConditionalCheckFailedException错误时,您才能继续将记录添加到服务器中。

如果您想根据两个字段 instanceId 和 imageId 的组合确保服务器中记录的唯一性,而不是仅使用 instanceId 将这些字段的串联值用作辅助表中的单个字段:

+----------------------------------------------+
|               Instance_Image                 |   
+----------------------------------------------+
| * instanceId_imageId   the hash key          |
+----------------------------------------------+
Run Code Online (Sandbox Code Playgroud)