Amazon DynamoDB
开发人员指南 (API Version 2012-08-10)
AWS 服务或AWS文档中描述的功能,可能因地区/位置而异。点 击 Getting Started with Amazon AWS to see specific differences applicable to the China (Beijing) Region.

在 DynamoDB 中处理项目

在 DynamoDB 中,项目 是属性的集合。每个属性都有各自的名称和值。属性值可以为标量、集或文档类型。有关更多信息,请参阅 Amazon DynamoDB:工作原理

DynamoDB 提供了用于基本的创建/读取/更新/删除 (CRUD) 功能的四项操作:

  • PutItem - 创建项目。

  • GetItem - 读取项目。

  • UpdateItem - 更新项目。

  • DeleteItem - 删除项目。

其中每项操作均需要您指定要处理的项目的主键。例如,要使用 GetItem 读取项目,您必须指定该项目的分区键和排序键 (如果适用)。

除了四项基本 CRUD 操作之外,DynamoDB 还提供了以下操作:

  • BatchGetItem - 从一个或多个表中读取最多 100 个项目。

  • BatchWriteItem - 在一个或多个表中删除最多 25 个项目。

这些批处理操作可将多项 CRUD 操作组合成一个请求。此外,批处理操作还可并行读取和写入项目以最大程度地减少响应延迟。

本节将介绍如何使用这些操作并包含了相关主题,例如有条件更新和原子计数器。本节还包括使用 AWS 开发工具包的示例代码。有关最佳实践,请参阅 针对项目的最佳实践

读取项目

要从 DynamoDB 表中读取项目,请使用 GetItem 操作。必需提供表的名称和所需项目的主键。

以下 AWS CLI 示例将展示如何从 ProductCatalog 表读取项目。

Copy
aws dynamodb get-item \ --table-name ProductCatalog \ --key '{"Id":{"N":"1"}}'

注意

使用 GetItem 时,您必须指定整个 主键,而不仅仅是部分主键。例如,如果某个表具有复合主键(分区键和排序键),您必须为分区键和排序键分别提供一个值。

默认情况下,GetItem 请求将执行最终一致性读取。您可以改用 ConsistentRead 参数来请求强一致性读取。(这将占用额外的读取容量单位,但会返回该项目的最新版本。)

GetItem 返回项目的所有属性。您可以使用投影表达式 来仅返回一部分属性。(有关更多信息,请参阅 投影表达式。)

要返回由 GetItem 占用的读取容量单位数,请将 ReturnConsumedCapacity 参数设置为 TOTAL

以下 AWS CLI 示例将演示一些可选的 GetItem 参数。

Copy
aws dynamodb get-item \ --table-name ProductCatalog \ --key '{"Id":{"N":"1"}}' \ --consistent-read \ --projection-expression "Description, Price, RelatedItems" \ --return-consumed-capacity TOTAL

写入项目

要创建、更新或删除 DynamoDB 表中的项目,请使用以下操作之一:

  • PutItem

  • UpdateItem

  • DeleteItem

对于这些操作中的每一项,您都需要指定完整的主键,而不仅仅是部分主键。例如,如果某个表具有复合主键(分区键和排序键),您必须为分区键和排序键分别提供一个值。

要返回其中任何操作占用的写入容量单位数,请将 ReturnConsumedCapacity 参数设置为以下项之一:

  • TOTAL - 返回占用的写入容量单位总数。

  • INDEXES - 返回占用的写入容量单位总数,其中包含表的小计和受该操作影响的任何二级索引es。

  • NONE - 不返回任何写入容量详细信息。(这是默认值。)

PutItem

PutItem 创建新项目。如果表中已存在具有相同键的项目,它将被替换为新项目。

将新项目写入到 Thread 表。Thread 的主键包含 ForumName (分区键) 和 Subject (排序键)。

Copy
aws dynamodb put-item \ --table-name Thread \ --item file://item.json

--item 的参数存储在文件 item.json 中:

Copy
{ "ForumName": {"S": "Amazon DynamoDB"}, "Subject": {"S": "New discussion thread"}, "Message": {"S": "First post in this thread"}, "LastPostedBy": {"S": "fred@example.com"}, "LastPostDateTime": {"S": "201603190422"} }

UpdateItem

如果带指定键的项目不存在,则 UpdateItem 会创建一个新项目。否则,它会修改现有项目的属性。

您可使用更新表达式 指定要修改的属性及其新值。(有关更多信息,请参阅 更新表达式。)在更新表达式内,您可使用表达式属性值作为实际值的占位符。(有关更多信息,请参阅 表达式属性值。)

修改 Thread 项目中的各种属性。可选 ReturnValues 参数按更新后的情况显示项目。(有关更多信息,请参阅 返回值。)

Copy
aws dynamodb update-item \ --table-name Thread \ --key file://key.json \ --update-expression "SET Answered = :zero, Replies = :zero, LastPostedBy = :lastpostedby" \ --expression-attribute-values file://expression-attribute-values.json \ --return-values ALL_NEW

--key 的参数存储在文件 key.json 中:

Copy
{ "ForumName": {"S": "Amazon DynamoDB"}, "Subject": {"S": "New discussion thread"} }

--expression-attribute-values 的参数存储在文件 expression-attribute-values.json 中:

Copy
{ ":zero": {"N":"0"}, ":lastpostedby": {"S":"barney@example.com"} }

DeleteItem

DeleteItem 删除带指定键的项目。

此 AWS CLI 示例展示了如何删除 Thread 项目。

Copy
aws dynamodb delete-item \ --table-name Thread \ --key file://key.json

返回值

在某些情况下,您可能希望 DynamoDB 按您修改特定属性值之前或之后的情况返回这些值。PutItemUpdateItemDeleteItem 操作均具有一个 ReturnValues 参数,您可使用该参数返回属性在修改前或修改后的值。

ReturnValues 的默认值为 NONE,这表示 DynamoDB 不会返回有关修改的属性的任何信息。

下面是 ReturnValues 的其他有效设置,这些设置由 DynamoDB API 操作组织:

PutItem

  • ReturnValuesALL_OLD

    • 如果您覆盖了现有项目,ALL_OLD 将按覆盖前的情况返回整个项目。

    • 如果您写入了不存在的项目,则 ALL_OLD 无效。

UpdateItem

UpdateItem 的最常见用途是更新现有项目。但是,UpdateItem 实际上会执行 upsert 操作,这意味着如果项目尚不存在,UpdateItem 将自动创建项目。

  • ReturnValues: ALL_OLD

    • 如果您更新了现有项目,ALL_OLD 将按更新前的情况返回整个项目。

    • 如果您更新了不存在的项目 (upsert),则 ALL_OLD 无效。

  • ReturnValues: ALL_NEW

    • 如果您更新了现有项目,ALL_NEW 将按更新后的情况返回整个项目。

    • 如果您更新了不存在的项目 (upsert),ALL_NEW 将返回整个项目。

  • ReturnValues: UPDATED_OLD

    • 如果您更新了现有项目,UPDATED_OLD 将仅返回已更新的属性 (按更新前的情况)。

    • 如果您更新了不存在的项目 (upsert),UPDATED_OLD 将无效。

  • ReturnValues: UPDATED_NEW

    • 如果您更新了现有项目,UPDATED_NEW 将仅返回受影响的属性 (按更新后的情况)。

    • 如果您更新了不存在的项目 (upsert),UPDATED_NEW 将仅返回已更新的属性 (按更新后的情况)。

DeleteItem

  • ReturnValues: ALL_OLD

    • 如果您删除了现有项目,ALL_OLD 将按删除前情况返回整个项目。

    • 如果您删除了不存在的项目,ALL_OLD 不会返回任何数据。

批量操作

对于需要读取和写入多个项目的应用程序,DynamoDB 提供了 BatchGetItemBatchWriteItem 操作。使用这些操作可减少从您的应用程序到 DynamoDB 的网络往返行程数。此外,DynamoDB 还可并行执行各个读取或写入操作。您的应用程序将受益于这种并行机制,并且无需管理并发度或线程。

批处理操作本质上是围绕多个读取或写入请求的包装程序。例如,如果一个 BatchGetItem 请求包含五个项目,则 DynamoDB 会代表您执行五次 GetItem 操作。同样,如果一个 BatchWriteItem 请求包含两个放置请求和四个删除请求,则 DynamoDB 会执行两次 PutItem 和四次 DeleteItem 请求。

通常,除非一个批处理操作中的所有 请求都失败,否则批处理操作不会失败。例如,假设您执行了一个 BatchGetItem 操作,但该批处理中的单独的 GetItem 请求之一失败。在这种情况下,BatchGetItem 会返回来自失败的 GetItem 请求的键和数据。该批处理中的其他 GetItem 请求不会受影响。

BatchGetItem

一个 BatchGetItem 操作最多可包含 100 个单独的 GetItem 请求且最多可检索 16 MB 的数据。此外,一个 BatchGetItem 操作可从多个表中检索项目。

Thread 表中检索两个项目,并使用投影表达式仅返回一部分属性。

Copy
aws dynamodb batch-get-item \ --request-items file://request-items.json

--request-items 的参数存储在文件 request-items.json 中:

Copy
{ "Thread": { "Keys": [ { "ForumName":{"S": "Amazon DynamoDB"}, "Subject":{"S": "DynamoDB Thread 1"} }, { "ForumName":{"S": "Amazon S3"}, "Subject":{"S": "S3 Thread 1"} } ], "ProjectionExpression":"ForumName, Subject, LastPostedDateTime, Replies" } }

BatchWriteItem

BatchWriteItem 操作最多可包含 25 个单独的 PutItemDeleteItem 请求且最多可写入 16 MB 的数据。(单个项目的最大大小为 400 KB。)此外,一个 BatchWriteItem 操作可在多个表中放置或删除项目。

注意

BatchWriteItem 不支持 UpdateItem 请求。

将两个项目写入到 ProductCatalog 表中。

Copy
aws dynamodb batch-write-item \ --request-items file://request-items.json

--request-items 的参数存储在文件 request-items.json 中:

Copy
{ "ProductCatalog": [ { "PutRequest": { "Item": { "Id": { "N": "601" }, "Description": { "S": "Snowboard" }, "QuantityOnHand": { "N": "5" }, "Price": { "N": "100" } } } }, { "PutRequest": { "Item": { "Id": { "N": "602" }, "Description": { "S": "Snow shovel" } } } } ] }

原子计数器

您可以使用 UpdateItem 操作来实施原子计数器 - 一种无条件递增的数字属性,不会干扰其他写入请求。(所有写入请求的应用顺序跟接收顺序相同。)使用原子计数器时,更新不是幂等的。换言之,该数字值将在您每次调用 UpdateItem 时递增。

您可使用原子计数器跟踪网站的访问者的数量。在这种情况下,您的应用程序将以某个数字值递增,无论其当前值如何。如果 UpdateItem 操作应失败,该应用程序只需重试该操作即可。这会产生更新两次计数器的风险,但您可能能够容忍对网站访问者的计数稍微偏多或偏少。

在无法容忍计数偏高多或偏少的情况下 (例如,在银行应用程序中),原子计数器将不适合使用。在这些情况下,使用有条件更新比使用原子计数器更安全。

有关更多信息,请参阅 对数值属性进行加减

以下 AWS CLI 示例以 5 为递增量提高产品的 Price。(由于 UpdateItem 不是幂等的,Price 将在您每次运行此示例时增加。)

Copy
aws dynamodb update-item \ --table-name ProductCatalog \ --key '{"Id": { "N": "601" }}' \ --update-expression "SET Price = Price + :incr" \ --expression-attribute-values '{":incr":{"N":"5"}}' \ --return-values UPDATED_NEW

有条件写入

默认情况下,DynamoDB 写入操作 (PutItemUpdateItemDeleteItem) 是无条件的:其中每项操作都会覆盖带指定主键的现有项目。

DynamoDB 可以选择性地对这些操作支持有条件写入。有条件写入仅在项目属性满足一个或多个预期条件时才会成功。否则,它会返回错误。有条件写入在很多情况下很有用。例如,您可能希望 PutItem 操作仅在尚不存在具有相同主键的项目时成功。或者,如果某个项目的其中一个属性具有一个特定值,您可以阻止 UpdateItem 操作修改该项目。

有条件写入在多个用户尝试修改同一项目的情况下很有用。请考虑下图,其中两位用户 (Alice 和 Bob) 正在处理 DynamoDB 表中的同一项目:

假设 Alice 使用 AWS CLI 将 Price 属性更新为 8:

Copy
aws dynamodb update-item \ --table-name ProductCatalog \ --key '{"Id":{"N":"1"}}' \ --update-expression "SET Price = :newval" \ --expression-attribute-values file://expression-attribute-values.json

--expression-attribute-values 的参数存储在文件 expression-attribute-values.json 中:

Copy
{ ":newval":{"N":"8"} }

现在假设 Bob 稍后发出一个相似的 UpdateItem 请求,但将 Price 更改为 12。对于 Bob,--expression-attribute-values 参数类似于以下形式:

Copy
{ ":newval":{"N":"12"} }

Bob 的请求成功,但 Alice 之前的更新丢失了。

要请求有条件 PutItemDeleteItemUpdateItem,请指定一个条件表达式。条件表达式 是一个包含属性名称、条件运算符和内置函数的字符串。整个表达式的计算结果必须为 true。否则,操作将失败。

现在考虑下图,该图展示了有条件写入将如何阻止 Alice 的更新被覆盖:

Alice 首次尝试将 Price 更新为 8,但仅在当前 Price 为 10 时才执行此操作:

Copy
aws dynamodb update-item \ --table-name ProductCatalog \ --key '{"Id":{"N":"1"}}' \ --update-expression "SET Price = :newval" \ --condition-expression "Price = :currval" \ --expression-attribute-values file://expression-attribute-values.json

--expression-attribute-values 的参数存储在文件 expression-attribute-values.json 中:

Copy
{ ":newval":{"N":"8"}, ":currval":{"N":"10"} }

由于条件的计算结果为 true,Alice 的更新成功了。

接下来,Bob 尝试将 Price 更新为 12,但仅在当前 Price 为 10 时才执行此操作。对于 Bob,--expression-attribute-values 参数类似于以下形式:

Copy
{ ":newval":{"N":"12"}, ":currval":{"N":"10"} }

由于 Alice 之前已将 Price 更改为 8,因此条件表达式的计算结果为 false,Bob 的更新失败。

有关更多信息,请参阅 条件表达式

有条件写入幂等性

有条件写入是幂等 的。这意味着,您可以向 DynamoDB 多次发送同一有条件写入请求,但在 DynamoDB 首次执行更新后,该请求不会对项目产生其他影响。

例如,假设您发出一个 UpdateItem 请求来以 3 为递增量提高某个项目的 Price,但仅在 Price 当前为 20 时才执行此操作。在已发送该请求但尚未获得返回的结果之间的时间内,网络出现了错误,您不知道该请求是否成功。由于条件写入是幂等的,您可以重试同一 UpdateItem 请求,而 DynamoDB 将仅在 Price 当前为 20 时更新项目。

有条件写入占用的容量单位

如果 ConditionExpression 在有条件写入过程中计算结果为 false,DynamoDB 仍会占用表的写入容量:

  • 如果项目当前在表中不存在,DynamoDB 将占用一个写入容量单位。

  • 如果项目已存在,则所占用的写入容量单位数将取决于项目的大小。例如,对 1 KB 项目的一次失败的有条件写入会占用一个写入容量单位。如果项目增大一倍,则失败的有条件写入会占用两个写入容量单位。

注意

写入操作仅占用写入容量单位。它们从不占用读取容量单位。

失败的有条件写入将返回 ConditionalCheckFailedException。发生这种情况时,您不会在响应中收到有关所占写入容量的任何信息。但是,您可以查看 Amazon CloudWatch 中的表的 ConsumedWriteCapacityUnits 指标。(有关更多信息,请参阅监控 DynamoDB 中的 DynamoDB 指标。)

要返回有条件写入过程中占用的写入容量单位的数量,请使用 ReturnConsumedCapacity 参数:

  • TOTAL - 返回占用的写入容量单位总数。

  • INDEXES - 返回占用的写入容量单位总数,其中包含表的小计和受该操作影响的任何二级索引es。

  • NONE - 不返回任何写入容量详细信息。(这是默认值。)

注意

与全局二级索引不同的是,local secondary index将其预置的吞吐容量与它的表共享。对local secondary index执行的读取和写入活动会占用表的预置的吞吐容量。