DynamoDB put-item ConditionalCheckFailedException

问题描述 投票:0回答:4

鉴于下面定义的表模式 (

create-table.json
),在使用
put-item
后跟
add-event1.json
调用
add-event2.json
后,我收到以下错误:

调用PutItem操作时出现客户端错误(ConditionalCheckFailedException):条件请求失败

为什么 ConditionExpression 不允许我写入两条记录? (我预计第二次操作后会有2条记录)

我怀疑这是因为使用了非关键条件,但我在docs中没有看到任何表明缺乏对非关键条件的支持。

创建表

$ aws dynamodb create-table --cli-input-json file://create-table.json

创建表.json

{
    "TableName": "EVENTS_TEST",
    "KeySchema": [
      { "AttributeName": "aggregateId", "KeyType": "HASH" },
      { "AttributeName": "streamRevision", "KeyType": "RANGE" }
    ],
    "AttributeDefinitions": [
      { "AttributeName": "aggregateId", "AttributeType": "S" },
      { "AttributeName": "streamRevision", "AttributeType": "N" }
    ],
    "ProvisionedThroughput": {
      "ReadCapacityUnits": 10,
      "WriteCapacityUnits": 10
    }
 }

添加第一条记录

$ aws dynamodb put-item --cli-input-json file://add-event1.json

add-event1.json

{
  "TableName": "EVENTS_TEST",
  "Item": {
    "aggregateId": { "S": "id" },
    "id": { "S": "119" },
    "context": { "S": "*" },
    "aggregate": { "S": "*" },
    "streamRevision": { "N": "0" },
    "commitId": { "S": "1119" },
    "commitSequence": { "N": "0" },
    "commitStamp": { "N": "1470185631511" },
    "dispatched": { "BOOL": false },
    "payload": { "S": "{ \"event\": \"bla\" }" }
  },
  "ExpressionAttributeNames": { "#name": "aggregate" },
  "ConditionExpression": "attribute_not_exists(aggregateId) and attribute_not_exists(streamRevision) and #name <> :name and context <> :ctx",
  "ExpressionAttributeValues": {
    ":name": { "S": "*" },
    ":ctx": { "S": "*" }
  }
}

添加第二条记录

$ aws dynamodb put-item --cli-input-json file://add-event2.json

add-event2.json

{
  "TableName": "EVENTS_TEST",
  "Item": {
    "aggregateId": { "S": "id" },
    "id": { "S": "123" },
    "context": { "S": "myCtx" },
    "aggregate": { "S": "myAgg" },
    "streamRevision": { "N": "0" },
    "commitId": { "S": "1123" },
    "commitSequence": { "N": "0" },
    "commitStamp": { "N": "1470185631551" },
    "dispatched": { "BOOL": false },
    "payload": { "S": "{ \"event\": \"bla2\" }" }
  },
  "ExpressionAttributeNames": { "#name": "aggregate" },
  "ConditionExpression": "aggregateId <> :id and streamRevision <> :rev and #name <> :name and context <> :ctx",
  "ExpressionAttributeValues": {
     ":id": { "S": "id" },
     ":rev": { "N": "0" },
     ":name": { "S": "myAgg" },
     ":ctx": { "S": "myCtx" }
  }
}
amazon-dynamodb
4个回答
28
投票

您的目标是保存这两条记录。这里有2个问题

  1. 根据您选择的哈希和范围键,不可能保存两条记录

哈希键和范围键的组合使记录具有唯一性。 事件 1 和事件 2 的哈希键和范围键具有相同的值。 因此,第二个放置项将简单地覆盖第一个记录。

  1. 您的 ConditionExpression 阻止记录 2 替换记录 1

ConditionExpression 在放置记录之前进行评估。您的表达式失败,因为当即将插入事件 2 时,DynamoDB 发现聚合 ID 为“id1”的记录已存在。 “attribute_not_exists(aggregateId)”条件失败,您会收到 ConditionalCheckFailedException 该表达式可防止记录 2 覆盖记录 1。

如果您想保存两条记录,您将必须选择另一种哈希键和/或范围键,以更好地代表数据项的唯一性。您无法使用 ConditionExpression 解决该问题。


1
投票

我收到类似的错误。

The conditional request failed (Service: AmazonDynamoDBv2; Status Code: 400; Error Code: ConditionalCheckFailedException; Request ID: SMNKMSKJNSHBSGHVGHSB)

就我而言,我没有在表中添加排序键,并且我的第二项与第一项具有相同的主键。添加排序键后它就起作用了。


0
投票

解决方案

表中已存在具有该 ID 的项目。

您需要为您尝试添加的项目创建一个唯一的 ID。


0
投票

在我的例子中,我得到了错误,因为我在数据库中有乐观锁,并且根据aws中的官方文档,表条目的客户端版本与服务器的版本不同,在我的例子中,有两个服务访问同一数据库并修改它.

带有版本号的乐观锁定 - https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBMapper.OptimisticLocking.html

ConditionalCheckFailedException 抛出如果:

您可以将乐观锁定与 @DynamoDBVersionAttribute 和 服务器上的版本值与客户端上的值不同 侧面。

您在保存数据时指定自己的条件约束 将 DynamoDBMapper 与 DynamoDBSaveExpression 和这些约束结合使用 失败了。

© www.soinside.com 2019 - 2024. All rights reserved.