仅 PK 上的 DynamoDB 更新项目条件
DynamoDB Update Item condition on PK only
我有一些 DynamoDB 数据,如下所示:
PK: SK:
subscriptionId | changeId | status | scheduled_for |
--------------------------------------------------------------
A | 19695a80-e3... | DONE | 2009-01-01 |
A | 3327f283-a1... | DONE | 2012-11-13 |
X | aebb5fe4-78... | DONE | 2019-06-24 |
X | 8982f726-69... | PENDING | 2022-01-01 |
如果提出新的更改请求,我目前取消旧的更改并按如下方式等待新的更改:
PK: SK:
subscriptionId | changeId | status | scheduled_for |
--------------------------------------------------------------
A | 19695a80-e3... | DONE | 2009-01-01 |
A | 3327f283-a1... | DONE | 2012-11-13 |
X | aebb5fe4-78... | DONE | 2019-06-24 |
X | 8982f726-69... | CANCELLED | 2022-01-01 |
X | 1f3380aa-f2... | PENDING | 2022-02-01 |
同一订阅的两个请求同时进入的可能性很小,所以我认为保证只有一个 'PENDING' 记录的最佳方法是在事务中使用 ConditionCheck并避免任何往返比赛条件 - 例如
// Only insert if there is no PENDING item for the subscriptionId
writeItems := []*dynamodb.TransactWriteItem{
{
ConditionCheck: &dynamodb.ConditionCheck{
TableName: aws.String("subscription_changes"),
ConditionExpression: aws.String("attribute_not_exists(changeId)"),
Key: map[string]*dynamodb.AttributeValue{
"status": {S: aws.String("PENDING")},
"subscriptionId": {S: aws.String(subscriptionId)},
},
},
},
{
Put: &dynamodb.Put{
TableName: aws.String("subscription_changes"),
Item: attributesMap,
},
},
}
...但是,DynamoDB 希望我在我的条件中包含排序键 (changeId),如果不查询数据我无法知道这一点(因此打开了两个线程出现竞争条件的可能性'win' 我们在 table).
中有两个 PENDING 项目
有办法吗?
在 SQL 中类似于:
INSERT subscription_items
(subscriptionId, changeId, status, ...)
SELECT 'X', '1f3380aa-f2...', 'PENDING', ...
WHERE NOT EXISTS (SELECT 1
FROM subscription_items
WHERE subscriptionId = ‘X’ AND status = 'PENDING')
确实,Dynamo 中一致性的一个限制是您需要准确地告诉 Dynamo 它应该对哪些项目 (PK/SK) 进行操作。正如您提到的,这在 SQL 中相对微不足道,但与 Dynamo 一样,另一方面是相对不可能实现 SQL 网络规模的方式...... :)
解决这个问题的一种方法是在您的交易中添加一个额外的“跟踪”项目,使用 PK X
和 SK current_pending
或类似的东西。在您的 TX 中,添加此项,并确认它不存在。这两个跟踪项本身是相互独立的,但它们不能同时成功创建,因为其中一个还没有 current_pending
SK。然后,当一个项目不再挂起时,也删除同一个 TX 中的 current_pending
项目以释放“锁定”。
Dynamo 中的很多事务和一致性问题都通过添加更多项来解决!
我有一些 DynamoDB 数据,如下所示:
PK: SK:
subscriptionId | changeId | status | scheduled_for |
--------------------------------------------------------------
A | 19695a80-e3... | DONE | 2009-01-01 |
A | 3327f283-a1... | DONE | 2012-11-13 |
X | aebb5fe4-78... | DONE | 2019-06-24 |
X | 8982f726-69... | PENDING | 2022-01-01 |
如果提出新的更改请求,我目前取消旧的更改并按如下方式等待新的更改:
PK: SK:
subscriptionId | changeId | status | scheduled_for |
--------------------------------------------------------------
A | 19695a80-e3... | DONE | 2009-01-01 |
A | 3327f283-a1... | DONE | 2012-11-13 |
X | aebb5fe4-78... | DONE | 2019-06-24 |
X | 8982f726-69... | CANCELLED | 2022-01-01 |
X | 1f3380aa-f2... | PENDING | 2022-02-01 |
同一订阅的两个请求同时进入的可能性很小,所以我认为保证只有一个 'PENDING' 记录的最佳方法是在事务中使用 ConditionCheck并避免任何往返比赛条件 - 例如
// Only insert if there is no PENDING item for the subscriptionId
writeItems := []*dynamodb.TransactWriteItem{
{
ConditionCheck: &dynamodb.ConditionCheck{
TableName: aws.String("subscription_changes"),
ConditionExpression: aws.String("attribute_not_exists(changeId)"),
Key: map[string]*dynamodb.AttributeValue{
"status": {S: aws.String("PENDING")},
"subscriptionId": {S: aws.String(subscriptionId)},
},
},
},
{
Put: &dynamodb.Put{
TableName: aws.String("subscription_changes"),
Item: attributesMap,
},
},
}
...但是,DynamoDB 希望我在我的条件中包含排序键 (changeId),如果不查询数据我无法知道这一点(因此打开了两个线程出现竞争条件的可能性'win' 我们在 table).
中有两个 PENDING 项目有办法吗?
在 SQL 中类似于:
INSERT subscription_items
(subscriptionId, changeId, status, ...)
SELECT 'X', '1f3380aa-f2...', 'PENDING', ...
WHERE NOT EXISTS (SELECT 1
FROM subscription_items
WHERE subscriptionId = ‘X’ AND status = 'PENDING')
确实,Dynamo 中一致性的一个限制是您需要准确地告诉 Dynamo 它应该对哪些项目 (PK/SK) 进行操作。正如您提到的,这在 SQL 中相对微不足道,但与 Dynamo 一样,另一方面是相对不可能实现 SQL 网络规模的方式...... :)
解决这个问题的一种方法是在您的交易中添加一个额外的“跟踪”项目,使用 PK X
和 SK current_pending
或类似的东西。在您的 TX 中,添加此项,并确认它不存在。这两个跟踪项本身是相互独立的,但它们不能同时成功创建,因为其中一个还没有 current_pending
SK。然后,当一个项目不再挂起时,也删除同一个 TX 中的 current_pending
项目以释放“锁定”。
Dynamo 中的很多事务和一致性问题都通过添加更多项来解决!