DynamoDB ReturnValues:拿回旧项或新项
默认情况下,一次 DynamoDB 写入除了成功之外什么都不返回。但你常常需要写入前后的数据 ——
改动之前的值,或改动之后的新值。最直白的办法是再做一次 GetItem,这既是一次额外的往返,也
是一次竞态:别人可以在中间写入。DynamoDB 用 ReturnValues 参数避开了这两点,它作为写入
本身的一部分,原子地把旧项或新项交还给你。
DynamoDB 中的 ReturnValues 有什么用?
ReturnValues 告诉 DynamoDB 写入操作在同一次调用中把项交还给你,从而跳过第二次 GetItem 及其带来的竞态。PutItem 和 DeleteItem 接受 NONE 或 ALL_OLD;UpdateItem 接受全部五个选项(NONE、ALL_OLD、UPDATED_OLD、ALL_NEW、UPDATED_NEW),以原子方式返回旧值或新值。
ReturnValues把项作为写入的一部分返回 —— 没有第二次读取,没有竞态。NONE(默认)—— 不返回任何东西。ALL_OLD—— 写入之前的整个项。UPDATED_OLD—— 仅更新所改动的那些属性的之前值。ALL_NEW—— 写入之后的整个项。UPDATED_NEW—— 仅改动过的属性的之后值。PutItem/DeleteItem只接受NONE或ALL_OLD;UpdateItem接受全部五个。
问题所在:你需要你刚刚覆盖掉的那个值
假设你运营一个客服台,一位客服把一张工单的状态从 open 改成 pending。你的审计日志需要记录
改动之前的状态是什么。没有 ReturnValues 的话你会:
GetItem读取当前状态,UpdateItem设置新状态。
在第 1 步和第 2 步之间,另一位客服可能改了状态 —— 现在你的审计日志记下的是一个陈旧的「之前」值。
更糟的是,这是一个逻辑操作用了两次调用。ReturnValues 把它收拢成单次原子的 UpdateItem,
返回写入时刻实际的旧状态。
五个选项,以及各自何时该用
UpdateItem 支持全套;选择的是你需要项的哪一部分以及写入的哪一侧:
ReturnValues | 返回 | 何时使用 |
|---|---|---|
NONE | 什么都不返回 | 你不需要拿回项(默认) |
ALL_OLD | 写入前的整个项 | 审计 /「我刚替换掉了什么?」 |
UPDATED_OLD | 写入前改动的属性 | 你只关心你动过的字段 |
ALL_NEW | 写入后的整个项 | 你需要把新鲜的完整项返回给调用方 |
UPDATED_NEW | 写入后改动的属性 | 读回一个你刚自增的计数器/值 |
UPDATED_NEW 是日常的主力:用一个更新表达式自增一个
计数器,并在同一次调用里读回新的总数,没有竞态。对于客服工单的审计,ALL_OLD(若你只记录状态
字段则用 UPDATED_OLD)能原子地捕获改动前的状态。
注意这种不对称:PutItem 和 DeleteItem 只支持 NONE 和 ALL_OLD —— 删除没有「新」值
可返回,而 put 的新值就是你发送的内容。只有原地修改的 UpdateItem 才提供全部五个。
AWS 文档
给出了确切的对照表。
在 DynoTable 中编写更新
用 DynamoDB 表达式构建器可视化地组装 UpdateItem 及其
更新表达式 —— 它会生成 SET/ADD 子句以及属性名和值映射。在应用里,当一次暂存的写入被提交后,
DynoTable 会显示生成的项,于是你能直接看到新状态。

陷阱与后续步骤
- 别用
GetItem-然后-写入来读取一次改动前后的值 —— 那是一次往返加一次竞态;用ReturnValues。 UPDATED_*只返回动过的属性 —— 若你需要整个项,用ALL_*。PutItem/DeleteItem无法返回新值 —— 只能用NONE/ALL_OLD。ReturnValues不是条件的替代品 —— 要守卫一次写入,加一个 条件表达式;要读回它的效果,用ReturnValues。 它们可以组合使用。- 相关: 更新表达式、 原子计数器。
想做编辑并看到改动前后,而不用脚本写两次调用吗?下载 DynoTable,直接编辑你的项。
原子计数器UPDATED_NEW
库存系统在每次写入时都会增加 version 或 stock 字段。的模式是一个 UpdateItem 与 ADD stock :inc 和 ReturnValues:更新_新:
UpdateItem PK=SKU#8842
UpdateExpression: ADD stock :one
ExpressionAttributeValues: {":one": {"N": "1"}}
ReturnValues: UPDATED_NEW
→ Attributes.stock.N == "41" (was 40)您仅收到更改后的属性图,而不是完整的项目 - 理想情况下商品很大,但呼叫者需要新的柜台。对于审计跟踪,必须捕获更改前的每个字段,切换到ALL_OLD。写入仍按项目大小的 UpdateItem 计费; ReturnValues 确实不添加单独的阅读费用 - DynamoDB 已加载该项目以应用更新。
容量备注
返回属性不会使写入本身的 WCU 成本增加一倍。你付钱根据每个AWS更新前后的项目大小进行写入规则,与响应负载中出现的属性数量无关。如果您想先 GetItem 然后 UpdateItem 记录旧值,那么您支付读加写的费用。更新中的ReturnValues: ALL_OLD删除了完整读取 — 以每秒 500 次更新的速度读取 2 KB 项目,大约可节省每秒 250 个最终一致的 RCU。
使用条件表达式进行组合
ReturnValues 和
condition expressions 撰写同一个电话。示例:仅在低于上限时增加 retryCount,并返回新计数:
ConditionExpression: retryCount < :max
UpdateExpression: ADD retryCount :one
ReturnValues: UPDATED_NEW如果条件失败,DynamoDB返回ConditionalCheckFailedException并且无属性负载 — 与空的成功更新不同
UPDATED_NEW 当一切都没有改变时。使用 expression builder 生成
UpdateExpression、条件和编组值映射在一起。
决策指南
| 你需要... | 设置 | 适用于 |
|---|---|---|
| 没有回来 | NONE | 放置、更新、删除 |
| 覆盖/删除之前的完整项目 | ALL_OLD | 放置、更新、删除 |
| 之前仅更改了字段 | UPDATED_OLD | 更新 |
| 补丁后的完整项目 | ALL_NEW | 更新 |
| 仅更改字段,之后 | UPDATED_NEW | 更新 |
删除并放置
DeleteItem 和 ReturnValues: ALL_OLD 是实现“弹出并返回”的方式队列项的语义 - 删除的行在 Attributes 中返回。有删除时没有ALL_NEW,因为该项目不再存在。当您覆盖现有项目时,PutItem 和 ALL_OLD 返回上一项
key — 对于交换工作流程很有用。当密钥不存在时,响应省略
Attributes。
在DynoTable验证
在项目编辑器中暂存属性更改:查看窗格显示旧的和新的提交前并排值 — 相同的信息 UPDATED_OLD 和
UPDATED_NEW 会返回,无需编写脚本。提交后,复制该行作为 JSON 通过网格的导出操作进行测试装置。


