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

Amazon DynamoDB 事务:工作原理

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

TransactWriteItems API

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

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

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

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

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

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

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

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

通过事务进行的更改在事务成功完成后,将传播到全局二级索引 (GSI)、DynamoDB 流并最终传播到备份。由于最终一致性,从按需或时间点恢复 (PITR) 备份还原的表可能包含最近事务所做的某些但非全部更改。

幂等性

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

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

有关幂等性的要点

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

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

写入错误处理

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

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

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

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

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

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

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

如果正在执行的 TransactWriteItems 操作与在 TransactWriteItems 操作中针对一个或多个项目的并发 PutItemUpdateItemDeleteItemTransactGetItems 请求冲突,则并发请求失败,并显示 TransactionCancelledException

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

TransactGetItems API

TransactGetItems 是一个同步读取操作,它可将多达 10 个 Get 操作分组在一起。这些操作的目标是同一个 AWS 账户和区域内的一个或多个 DynamoDB 表中最多 10 个不同的项目。

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

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

读取错误处理

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

  • 当正在执行的 TransactGetItems 操作与并发 PutItemUpdateItemDeleteItemTransactWriteItems 请求冲突时。在这种情况下,TransactGetItems 操作将失败,并显示 TransactionCancelledException

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

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

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

DynamoDB 事务的隔离级别

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

可序列化

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

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

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

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

  • TransactWriteItems 操作与 TransactGetItems 操作之间。

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

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

读取已提交

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

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

摘要表

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

运算 隔离级别

DeleteItem

可序列化

PutItem

可序列化

UpdateItem

可序列化

GetItem

可序列化

BatchGetItem

读取已提交*

BatchWriteItem

不可序列化*

Query

读取已提交

Scan

读取已提交

其他事务操作

可序列化

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

事务的容量管理

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

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

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

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

事务的最佳实践

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

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

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

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

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

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

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

与其他 DynamoDB 功能集成

以下 DynamoDB 功能目前不支持 DynamoDB 事务:

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

  • DynamoDB Accelerator (DAX)、本地 DynamoDB 或 DynamoDB 映射器目前不支持事务操作。

DynamoDB 事务与 AWSLabs 事务客户端库

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