deno.com
本頁面

交易

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

您找到需要的資訊了嗎?

隱私權政策