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 是日常英雄:用一個
update expression 遞增一個計數器,並在同一次呼叫中
讀回新的總計,沒有競態。對於支援工單的稽核,ALL_OLD(若你只記錄狀態欄位則為
UPDATED_OLD)能以原子方式擷取更改前的狀態。
注意這個不對稱:PutItem 與 DeleteItem 只支援 NONE 與 ALL_OLD — 刪除沒有「新」
值可傳回,而一個 put 的新值就是你送出去的東西。只有就地變更的 UpdateItem 才提供全部五個。
AWS 文件記載了
確切的對照表。
在 DynoTable 中撰寫更新
用 DynamoDB 表達式建構器以視覺化方式組裝 UpdateItem
及其 update expression — 它會產生 SET/ADD 子句加上屬性名稱與值的映射。在應用程式中,
DynoTable 會在一筆暫存的寫入提交後顯示產生的項目,因此你能直接看到新的狀態。

陷阱與後續步驟
- 別用
GetItem然後寫入來讀取一次更改前後的值 — 那是一次往返加一個競態; 請使用ReturnValues。 UPDATED_*只傳回動過的屬性 — 若你需要整個項目,請用ALL_*。PutItem/DeleteItem無法傳回新值 — 只有NONE/ALL_OLD。ReturnValues不是 condition 的替代品 — 要保護一次寫入,請加上 condition expression;要讀回它的效果, 請用ReturnValues。兩者可以組合使用。- 相關: update expressions、 原子計數器。
想在不寫腳本做兩次呼叫的情況下進行編輯並看到前後對照嗎? 下載 DynoTable,直接編輯你的項目。


