鉴于下面定义的表模式 (
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" }
}
}
您的目标是保存这两条记录。这里有2个问题
哈希键和范围键的组合使记录具有唯一性。 事件 1 和事件 2 的哈希键和范围键具有相同的值。 因此,第二个放置项将简单地覆盖第一个记录。
ConditionExpression 在放置记录之前进行评估。您的表达式失败,因为当即将插入事件 2 时,DynamoDB 发现聚合 ID 为“id1”的记录已存在。 “attribute_not_exists(aggregateId)”条件失败,您会收到 ConditionalCheckFailedException 该表达式可防止记录 2 覆盖记录 1。
如果您想保存两条记录,您将必须选择另一种哈希键和/或范围键,以更好地代表数据项的唯一性。您无法使用 ConditionExpression 解决该问题。
我收到类似的错误。
The conditional request failed (Service: AmazonDynamoDBv2; Status Code: 400; Error Code: ConditionalCheckFailedException; Request ID: SMNKMSKJNSHBSGHVGHSB)
就我而言,我没有在表中添加排序键,并且我的第二项与第一项具有相同的主键。添加排序键后它就起作用了。
解决方案
表中已存在具有该 ID 的项目。
您需要为您尝试添加的项目创建一个唯一的 ID。
在我的例子中,我得到了错误,因为我在数据库中有乐观锁,并且根据aws中的官方文档,表条目的客户端版本与服务器的版本不同,在我的例子中,有两个服务访问同一数据库并修改它.
带有版本号的乐观锁定 - https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBMapper.OptimisticLocking.html
ConditionalCheckFailedException 抛出如果:
您可以将乐观锁定与 @DynamoDBVersionAttribute 和 服务器上的版本值与客户端上的值不同 侧面。
您在保存数据时指定自己的条件约束 将 DynamoDBMapper 与 DynamoDBSaveExpression 和这些约束结合使用 失败了。