Amazon DynamoDB
开发人员指南 (API 版本 2012-08-10)
AWS 文档中描述的 AWS 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅中国的 AWS 服务入门

Amazon DynamoDB 事务:工作原理

借助 Amazon DynamoDB 事务,您可以将多个操作分组在一起,并将它们作为单个“要么全有要么全无”的 TransactWriteItemsTransactGetItems 操作提交。以下各部分介绍有关在 DynamoDB 中使用事务操作的 API 操作、容量管理、最佳实践和其他详细信息。

TransactWriteItems API

TransactWriteItems 是一个同步和幂等的写入操作,它将最多 25 个写入操作分组在单个“要么全有要么全无”操作中。这些操作的目标是同一个 AWS 账户和同一个区域内的一个或多个 DynamoDB 表中最多 25 个不同的项目。事务中项目的合计大小不能超过 4 MB。这些操作以原子方式完成,以便所有操作都成功或都失败。

TransactWriteItems 不同于 BatchWriteItem 操作,因为前者包含的所有操作必须成功完成,否则根本不会进行任何更改。借助 BatchWriteItem 操作,批处理中的某些操作可能获得成功,而其他操作失败。

您不能将同一个事务中的多个操作指向同一个项目。例如,您不能在同一个事务中对相同项目既执行 ConditionCheck 又执行 Update 操作。

您可向事务添加下列类型的操作:

  • Put — 启动 PutItem 操作以创建一个新项目,或者将旧项目替换为新项目(有条件或未指定任何条件)。

  • Update — 启动 UpdateItem 操作以编辑现有项目的属性,或者将新项目添加到表中(如果它不存在)。使用此操作有条件或无条件添加、删除或更新现有项目的属性。

  • Delete — 启动 DeleteItem 操作,以删除表中由其主键标识的单个项目。

  • ConditionCheck — 检查项目是否存在,或者检查项目特定属性的条件。

事务完成后,通过该事务进行的更改将传播到全局二级索引 (GSI)、流和备份。由于传播并不具有即时性,如果某个表从备份还原到传播中的时间点,则可能会包含在近期事务中所做的部分而非全部更改。

幂等性

当您执行 TransactWriteItems 调用时,可以选择包含客户端令牌,以确保请求是幂等的。通过使事务成为幂等的,如果相同操作由于连接超时或其他连接问题而多次提交,则可帮助防止出现应用程序错误。

如果原始 TransactWriteItems 调用得成功,则使用相同客户端令牌的后续 TransactWriteItems 调用将成功返回,而不做任何更改。如果设置了 ReturnConsumedCapacity 参数,则初始 TransactWriteItems 调用将返回在进行更改时占用的写入容量单位数。使用相同客户端令牌的后续 TransactWriteItems 调用将返回在读取项目时占用的读取容量单位数。

有关幂等性的要点

  • 客户端令牌在使用它的请求完成后的 10 分钟内有效。10 分钟后,任何使用相同客户端令牌的请求都将被视为一个新请求。10 分钟后,您不应为同一请求使用重新相同的客户端令牌。

  • 如果您在 10 分钟的幂等性时段内使用相同的客户端令牌重复请求,但更改了某个其他请求参数,则 DynamoDB 将返回 IdempotentParameterMismatch 异常。

写入错误处理

写入事务在以下情况下不会成功:

  • 其中一个条件表达式中的条件未得到满足时。

  • 因为同一个 TransactWriteItems 操作中的多个操作指向同一个项目而导致发生事务验证错误时。

  • TransactWriteItems 请求与 TransactWriteItems 请求中针对一个或多个项目的正在执行的 TransactWriteItems 操作冲突时。在这种情况下,请求将失败并显示 TransactionCanceledException

  • 当完成事务所需的预置容量不足时。

  • 当项目大小变得过大(大于 400 KB),或者本地二级索引 (LSI) 变得过大,或者由于事务所做更改导致发生类似的验证错误时。

  • 出现用户错误(如数据格式无效)时。

有关如何处理与 TransactWriteItems 操作的冲突的更多信息,请参阅DynamoDB 中的事务冲突处理

TransactGetItems API

TransactGetItems 是一个同步读取操作,它可将多达 25 个 Get 操作分组在一起。这些操作的目标是同一个 AWS 账户和区域内的一个或多个 DynamoDB 表中最多 25 个不同的项目。事务中项目的合计大小不能超过 4 MB。

Get 以原子方式执行,以便所有操作都成功或都失败:

  • Get — 启动 GetItem 操作,以检索具有给定主键的项目的一组属性。如果找不到匹配项目,Get 将不返回任何数据。

读取错误处理

读取事务在以下情况下不会成功:

  • TransactGetItems 请求与 TransactGetItems 请求中针对一个或多个项目的正在执行的 TransactWriteItems 操作冲突时。在这种情况下,请求将失败并显示 TransactionCanceledException

  • 当完成事务所需的预置容量不足时。

  • 出现用户错误(如数据格式无效)时。

有关如何处理与 TransactGetItems 操作的冲突的更多信息,请参阅 DynamoDB 中的事务冲突处理

DynamoDB 事务的隔离级别

事务操作的隔离级别(TransactWriteItemsTransactGetItems)和其他操作如下所示。

可序列化

可序列化隔离可确保多个并发操作的结果相同,就像当前操作在前一个操作完成之前不会开始。

以下操作类型之间具有可序列化隔离:

  • 在任何事务操作与任何标准写入操作(PutItemUpdateItemDeleteItem)之间。

  • 在任何事务操作与任何标准读取操作 (GetItem) 之间。

  • TransactWriteItems 操作与 TransactGetItems 操作之间。

尽管在事务操作与 BatchWriteItem 操作中的每个单独标准写入之间具有可序列化隔离,但作为一个整体,在事务与 BatchWriteItem 操作之间没有可序列化隔离。

类似地,事务操作与 BatchGetItem 操作中的单个 GetItems 之间的隔离级别是可序列化的。但是事务和作为一个单元的 BatchGetItem 操作之间的隔离级别是读取已提交

读取已提交

读取已提交隔离可确保读取操作始终为项目返回提交的值。读取已提交隔离无法防止在读取操作后立即修改项目。

隔离级别在任何事务操作与涉及多个标准读取(BatchGetItemQueryScan)的任何读取操作之间为读取已提交。如果事务写入在 BatchGetItemQueryScan 操作中间更新项目,则读取操作返回新的已提交值。

操作摘要

简而言之,下表显示事务操作(TransactWriteItemsTransactGetItems)与其他操作之间的隔离级别。

运算 隔离级别

DeleteItem

可序列化

PutItem

可序列化

UpdateItem

可序列化

GetItem

可序列化

BatchGetItem

读取已提交*

BatchWriteItem

不可序列化*

Query

读取已提交

Scan

读取已提交

其他事务操作

可序列化

标记星号 (*) 的级别作为一个整体适用于操作。但是,这些操作内的各个操作具有可序列化隔离级别。

DynamoDB 中的事务冲突处理

事务内的项目上的并发项级请求期间可能会发生事务冲突。在以下情况下可能发生事务冲突:

  • 项目的 PutItemUpdateItemDeleteItem 请求与包含相同项目的正在进行的 TransactWriteItems 请求冲突。

  • TransactWriteItems 请求中的某个项目是另一个正在进行的 TransactWriteItems 请求的一部分。

  • TransactGetItems 请求中的某个项目是正在进行的 TransactWriteItemsBatchWriteItemPutItemUpdateItemDeleteItem 请求的一部分。

注意

  • PutItemUpdateItemDeleteItem 请求被拒绝时,请求会失败,并显示 TransactionConflictException

  • 如果 TransactWriteItemsTransactGetItems 任何项目级别请求被拒绝,则请求将失败并显示 TransactionCanceledException

    如果您使用的是 AWS SDK for Java,则该异常包含 CancellationReasons 列表,该列表根据 TransactItems 请求参数中的项目列表排序。对于其他语言,列表的字符串表示形式包含在异常的错误消息中。

  • 但是,如果正在执行的 TransactWriteItemsTransactGetItems 操作与并发 GetItem 请求冲突,则这两个操作都会成功。

对于每个失败的项目级别请求,TransactionConflict CloudWatch metric 指标会递增。

在 DynamoDB Accelerator (DAX) 中使用事务 API

TransactWriteItemsTransactGetItems 在 DynamoDB Accelerator (DAX) 中都受支持,并且其隔离级别与 DynamoDB 中的相同。

TransactWriteItems 通过 DAX 进行写入。DAX 将 TransactWriteItems 调用传递到 DynamoDB 并返回响应。为了在写入后填充缓存,DAX 会在后台对 TransactWriteItems 操作中的每个项目调用 TransactGetItems,这将使用额外的读取容量单位。(有关更多信息,请参阅 事务的容量管理。) 利用此功能,您可以保持应用程序逻辑的简单性,并将 DAX 同时用于事务操作和非事务操作。

TransactGetItems 调用将通过 DAX 进行传递,而不会在本地缓存项目。这与 DAX 中的强一致性读取 API 的行为相同。

事务的容量管理

无需其他成本即可为 DynamoDB 表启用事务。您只需对作为事务一部分的读写操作付费。DynamoDB 在事务中对于每个项目执行两次基础读写:一次是准备事务,一次是提交事务。这两个基础读/写操作显示在 Amazon CloudWatch 指标中。

当您为表预配置容量时,规划事务 API 需要的其他读取和写入。例如,假设您的应用程序每秒执行一个事务,并且每个事务在表中写入三个 500 字节的项目。每个项目需要两个写入容量单位 (WCU):一个用于准备事务,一个用于提交事务。因此,您需要为表预置六个 WCU。

如果您在前面的示例中使用 DynamoDB Accelerator (DAX),则还将为 TransactWriteItems 调用中的每个项目使用两个读取容量单位 (RCU)。因此,您需要为表预配置另外六个 RCU。

同样,如果您的应用程序每秒执行一个读取事务,并且每个事务读取表中三个 500 字节的项目,则您需要为表预置六个读取容量单位 (RCU)。读取每个项目需要两个 RCU:一个用于准备事务,一个用于提交事务。

此外,默认的 SDK 行为是在引发 TransactionInProgressException 异常时重试事务。规划这些重试所占用的其他读取容量单位 (RCU)。这同样适用于您使用 ClientRequestToken 在您自己的代码中重试事务。

事务的最佳实践

使用 DynamoDB 事务时,请考虑以下建议的实践。

  • 对表启用自动扩展功能,或者确保您已预置了足够的吞吐容量,以便为事务中的每个项目执行两个读取或写入操作。

  • 如果您未使用 AWS 提供的开发工具包,则在进行 TransactWriteItems 调用时加入 ClientRequestToken 属性,以确保请求具有幂等性。

  • 如果不必要,请勿将操作分组在一个事务中。例如,如果具有 10 个操作的单个事务可以分解为多个事务而不会妨碍应用程序正确性,则建议您拆分此事务。更简单的事务可提高吞吐量,且更可能成功。

  • 同时更新相同项目的多个事务可能导致冲突而取消事务。我们建议您遵循 DynamoDB数据建模的最佳实践,以最大限度地减少此类冲突。

  • 如果一组属性经常跨多个项目作为单个事务的一部分进行更新,则考虑将这些属性分组到一个项目,以减小事务的范围。

  • 避免使用事务来成批注入数据。对于成批写入,使用 BatchWriteItem 则更好。

将事务 API 与全局表一起使用

默认情况下对全局表禁用事务操作。如果您要对全局表启用事务,请联系 AWS Support

DynamoDB 事务与 AWSLabs 事务客户端库

DynamoDB 事务为 AWSLabs 事务客户端库提供了更经济实惠、强大且高性能的替代方式。我们建议您更新应用程序,以使用原生服务器端事务 API。