本頁面
交易
Deno KV 儲存使用樂觀並行控制交易,而非如 PostgreSQL 或 MySQL 等許多 SQL 系統的互動式交易。此方法採用版本戳記,代表給定鍵的值的目前版本,以管理對共用資源的並行存取,而無需使用鎖定。當執行讀取操作時,系統除了傳回值之外,還會傳回相關鍵的版本戳記。
為了執行交易,會執行一個原子操作,其中可能包含多個變更動作(例如設定或刪除)。除了這些動作之外,還提供鍵+版本戳記配對作為交易成功的條件。只有在指定的版本戳記與資料庫中相應鍵的值的目前版本相符時,樂觀並行控制交易才會提交。此交易模型確保資料一致性和完整性,同時允許 Deno KV 儲存內的並行互動。
由於 OCC 交易是樂觀的,因此它們可能會在提交時失敗,因為原子操作中指定的版本約束遭到違反。當代理程式在讀取和提交之間更新交易中使用的鍵時,就會發生這種情況。發生這種情況時,執行交易的代理程式必須重試交易。
為了說明如何在 Deno KV 中使用 OCC 交易,此範例示範如何為帳戶分類帳實作 transferFunds(from: string, to: string, amount: number)
函數。帳戶分類帳將每個帳戶的餘額儲存在鍵值儲存中。鍵會以 "account"
為前綴,後跟帳戶識別碼:["account", "alice"]
。為每個鍵儲存的值是一個數字,代表帳戶餘額。
以下是實作此 transferFunds
函數的逐步範例
async function transferFunds(sender: string, receiver: string, amount: number) {
if (amount <= 0) throw new Error("Amount must be positive");
// Construct the KV keys for the sender and receiver accounts.
const senderKey = ["account", sender];
const receiverKey = ["account", receiver];
// Retry the transaction until it succeeds.
let res = { ok: false };
while (!res.ok) {
// Read the current balance of both accounts.
const [senderRes, receiverRes] = await kv.getMany([senderKey, receiverKey]);
if (senderRes.value === null) {
throw new Error(`Account ${sender} not found`);
}
if (receiverRes.value === null) {
throw new Error(`Account ${receiver} not found`);
}
const senderBalance = senderRes.value;
const receiverBalance = receiverRes.value;
// Ensure the sender has a sufficient balance to complete the transfer.
if (senderBalance < amount) {
throw new Error(
`Insufficient funds to transfer ${amount} from ${sender}`,
);
}
// Perform the transfer.
const newSenderBalance = senderBalance - amount;
const newReceiverBalance = receiverBalance + amount;
// Attempt to commit the transaction. `res` returns an object with
// `ok: false` if the transaction fails to commit due to a check failure
// (i.e. the versionstamp for a key has changed)
res = await kv.atomic()
.check(senderRes) // Ensure the sender's balance hasn't changed.
.check(receiverRes) // Ensure the receiver's balance hasn't changed.
.set(senderKey, newSenderBalance) // Update the sender's balance.
.set(receiverKey, newReceiverBalance) // Update the receiver's balance.
.commit();
}
}
在此範例中,transferFunds
函數會讀取兩個帳戶的餘額和版本戳記,計算轉帳後的新餘額,並檢查帳戶 A 中是否有足夠的資金。然後,它會執行原子操作,設定具有版本戳記約束的新餘額。如果交易成功,迴圈就會結束。如果版本約束遭到違反,交易就會失敗,而迴圈會重試交易,直到成功為止。
限制 跳到標題
除了最大鍵大小為 2 KiB 和最大值大小為 64 KiB 之外,Deno KV 交易 API 還有某些限制
- 每次
kv.getMany()
的最大鍵數: 10 - 每次
kv.list()
的最大批次大小: 1000 - 原子操作中的最大檢查次數: 100
- 原子操作中的最大變更次數: 1000
- 原子操作的最大總大小:800 KiB。這包括檢查和變更中的所有鍵和值,以及編碼額外負荷也計入此限制。
- 最大鍵總大小:90 KiB。這包括檢查和變更中的所有鍵,以及編碼額外負荷也計入此限制。
- 每次
kv.watch()
的最大監看鍵數:10