为什么使用Java DynamoDB AWS SDK时会出现“提供的关键元素与架构不匹配”错误?

xwmevbvl  于 2022-12-28  发布在  Java
关注(0)|答案(2)|浏览(173)

我尝试用DynamoDB实现一种方法,允许只插入项目而不更新/替换项目(以实现某种级别的事务控制)。因此,我在AWS DynamoDB中配置了以下DB Schema:

PartitionKey="driveUniqueId (String)"
SortKey="createTime (String)"

现在,如果我运行下面的代码片段,操作就会工作,记录就会创建。

String currentTime = LocalTime.now().toString();
dynamoDbClient.transactWriteItems(TransactWriteItemsRequest.builder()
  .transactItems(
    TransactWriteItem.builder().put(
      Put.builder()
        .tableName(tableName)
        .item(Map.of(
          "driveUniqueId", AttributeValue.builder().s("789").build(),
          "createTime", AttributeValue.builder().s(currentTime).build()))
      .build())
    .build())
  .build());

然而,如果我运行下面的代码片段,添加conditionCheck以防止替换,那么我会得到下面的错误:

dynamoDbClient.transactWriteItems(TransactWriteItemsRequest.builder()
  .transactItems(
    TransactWriteItem.builder().put(
      Put.builder()
        .tableName(tableName)
        .item(Map.of(
          "driveUniqueId", AttributeValue.builder().s("123").build(),
          "createTime", AttributeValue.builder().s(currentTime).build()))
      .build())
    .build(),
    TransactWriteItem.builder().conditionCheck(
      ConditionCheck.builder()
        .tableName(tableName)
        .key(Map.of(
          "driveUniqueId", AttributeValue.builder().s("123").build()))                                    
        .conditionExpression("attribute_not_exists(driveUniqueId)")
      .build())
    .build())
  .build());
/*
Error: 
CancellationReason(Code=None)
CancellationReason(Code=ValidationError, Message=The provided key element does not match the schema)
*/

我不明白为什么在第二次写操作中指定的条件不能将“driveUniqueId”理解为schema的一部分。我使用Quarkus、Java 17和AWS SDK 2.17.291运行此代码。

zaq34kh6

zaq34kh61#

您的条件检查导致验证错误,因为您没有包括项sork key createTime
与对DynamoDB的任何写入一样,您必须包括完整的主键、分区和排序键。
此外,您可能不需要使用事务,单项操作是ACID兼容的,因此您可以简单地使用带有条件检查的PutItem

njthzxwz

njthzxwz2#

这是我基于@Lee Hanningan回应的最终解决方案。

/**
 * This method guarantees that a Item with a {@param uniqueId} will be processed only once
 * by the POD who grabbed its lock (a.k.a. being the first to insert the Item into DynamoDB table).
 * If another POD tries to re-process the same Item in parallel or in the future it'll fail.
 *
 * This property guarantees that Item will contribute to the process only once, in case of a POD 
 * network partition not acknowledging to SQS that a Item was processed successfully.
 *
 * @param uniqueId
 * @return isItemLocked.
 */
public boolean insertAndLockProcessingToItem(final String uniqueId) {
    boolean itemLockedToBeProcessed;
    try {
        String currentTime = LocalDateTime.now().toString();
        dynamoDbClient.putItem(PutItemRequest.builder()
            .tableName(TABLE_NAME)
            .item(Map.of(
                "uniqueId", AttributeValue.builder().s(uniqueId).build(),
                "createTime", AttributeValue.builder().s(currentTime).build()))
            .conditionExpression("attribute_not_exists(uniqueId)")
        .build());
        itemLockedToBeProcessed = true;
    } catch (final ConditionalCheckFailedException ccfe) {
        itemLockedToBeProcessed = false;
    } catch (final Exception ex) {
        throw new RuntimeException(ex);
    }
    return itemLockedToBeProcessed;
}

相关问题