使用DynamoDB作为单个操作执行INSERT或UPDATE

时间:2015-07-05 11:45:59

标签: amazon-web-services amazon-dynamodb

我们正在使用DynamoDB来计算用户操作,并且必须插入或更新项目,具体取决于它已存在的内容。代码还必须更新计数器。现在我们通过两个步骤完成此任务:

using (var client = AWSClientFactory.CreateAmazonDynamoDBClient(RegionEndpoint.USEast1))
{
    var table = Table.LoadTable(client, TableName);
    var item = await table.GetItemAsync(id);
    if (item == null)
    {
        // row not exists -> insert & return 1
        var document = new Document();
        document["Id"] = id;
        document["Counter"] = 1;
        await table.PutItemAsync(document);
        return 1;
    }
    // row exists -> increment counter & update
    var counter = item["Counter"].AsInt();
    item["Counter"] = counter + 1;
    await table.UpdateItemAsync(item);
    return counter + 1;
}

代码的问题在于它增加了延迟时间&服务器负载。我希望通过一次操作来完成这项工作。我认为这应该可以使用conditional expressions,但我无法弄清楚如何使用.NET SDK来实现这一点。

2 个答案:

答案 0 :(得分:1)

要小心自己递增计数器,因为如果你的应用的多个实例可以递增计数器,你可能会遇到竞争条件。而是使用DynamoDB Atomic Counters。例如,我的ruby代码使用以下(较旧的)递增计数器的方式调用UpdateItem API:

{"counter" => {value: {n: "1"}, action: "ADD"}}

更新的方法是使用我尚未实施的Update Expression。此外,如果计数器/项目不存在,它将假定值为0并将计数器增加到1.

答案 1 :(得分:0)

您的代码中存在竞争条件。 2个不同的工人可能同时创建该项目。

您尝试做的推荐模式是:

  • 如果项目不存在则创建。
  • 原子计数器更新"计数"

因此,而不是3个操作(获取,放置,更新) - 也有竞争条件 - 在这种情况下,您将只有2个操作(以及正确的行为)

希望这会有所帮助。