Cloud Datastore 交易

「交易」是指在最多 25 個實體群組中的一或多個實體上執行的一組 Datastore 操作。每筆交易都不可分割,這代表交易絕不會部分完成。換句話說,交易中的操作不是全部完成,就是全部不予進行。

使用交易

交易的最長持續時間為 270 秒,30 秒後會有 10 秒的閒置到期時間。

如有以下情形,操作可能會失敗:

  • 在同一個實體群組上嘗試進行太多並行修改。
  • 交易超過資源限制。
  • Datastore 發生內部錯誤。

在這些情況下,Datastore API 都會傳回錯誤訊息。

交易是 Datastore 的選用功能,您不一定要透過交易才能執行 Datastore 操作。

應用程式可以在單一交易中執行一組陳述式和 Datastore 作業,這樣一來,假如任何陳述式或作業引發例外狀況,系統就不會套用組合中的任何 Datastore 作業。應用程式會定義要在交易中執行的動作。

下列程式碼片段顯示如何使用 Datastore API 執行交易。在本範例中,系統會將金額從一個帳戶轉至另一個帳戶。

C#

如要瞭解如何安裝及使用 Cloud Datastore 的用戶端程式庫,請參閱「Cloud Datastore 用戶端程式庫」一文。詳情請參閱 Cloud Datastore C# API 參考說明文件

如要向 Cloud Datastore 進行驗證,請設定應用程式預設憑證。 詳情請參閱「為本機開發環境設定驗證」。

private void TransferFunds(Key fromKey, Key toKey, long amount)
{
    using (var transaction = _db.BeginTransaction())
    {
        var entities = transaction.Lookup(fromKey, toKey);
        entities[0]["balance"].IntegerValue -= amount;
        entities[1]["balance"].IntegerValue += amount;
        transaction.Update(entities);
        transaction.Commit();
    }
}

Go

如要瞭解如何安裝及使用 Cloud Datastore 的用戶端程式庫,請參閱「Cloud Datastore 用戶端程式庫」一文。詳情請參閱 Cloud Datastore Go API 參考說明文件

如要向 Cloud Datastore 進行驗證,請設定應用程式預設憑證。 詳情請參閱「為本機開發環境設定驗證」。

type BankAccount struct {
	Balance int
}

const amount = 50
keys := []*datastore.Key{to, from}
tx, err := client.NewTransaction(ctx)
if err != nil {
	log.Fatalf("client.NewTransaction: %v", err)
}
accs := make([]BankAccount, 2)
if err := tx.GetMulti(keys, accs); err != nil {
	tx.Rollback()
	log.Fatalf("tx.GetMulti: %v", err)
}
accs[0].Balance += amount
accs[1].Balance -= amount
if _, err := tx.PutMulti(keys, accs); err != nil {
	tx.Rollback()
	log.Fatalf("tx.PutMulti: %v", err)
}
if _, err = tx.Commit(); err != nil {
	log.Fatalf("tx.Commit: %v", err)
}

Java

如要瞭解如何安裝及使用 Cloud Datastore 的用戶端程式庫,請參閱「Cloud Datastore 用戶端程式庫」一文。詳情請參閱 Cloud Datastore Java API 參考說明文件

如要向 Cloud Datastore 進行驗證,請設定應用程式預設憑證。 詳情請參閱「為本機開發環境設定驗證」。

void transferFunds(Key fromKey, Key toKey, long amount) {
  Transaction txn = datastore.newTransaction();
  try {
    List<Entity> entities = txn.fetch(fromKey, toKey);
    Entity from = entities.get(0);
    Entity updatedFrom =
        Entity.newBuilder(from).set("balance", from.getLong("balance") - amount).build();
    Entity to = entities.get(1);
    Entity updatedTo =
        Entity.newBuilder(to).set("balance", to.getLong("balance") + amount).build();
    txn.put(updatedFrom, updatedTo);
    txn.commit();
  } finally {
    if (txn.isActive()) {
      txn.rollback();
    }
  }
}

Node.js

如要瞭解如何安裝及使用 Cloud Datastore 的用戶端程式庫,請參閱「Cloud Datastore 用戶端程式庫」一文。詳情請參閱 Cloud Datastore Node.js API 參考說明文件

如要向 Cloud Datastore 進行驗證,請設定應用程式預設憑證。 詳情請參閱「為本機開發環境設定驗證」。

async function transferFunds(fromKey, toKey, amount) {
  const transaction = datastore.transaction();
  await transaction.run();
  const results = await Promise.all([
    transaction.get(fromKey),
    transaction.get(toKey),
  ]);
  const accounts = results.map(result => result[0]);

  accounts[0].balance -= amount;
  accounts[1].balance += amount;

  transaction.save([
    {
      key: fromKey,
      data: accounts[0],
    },
    {
      key: toKey,
      data: accounts[1],
    },
  ]);

  return await transaction.commit();
}

PHP

如要瞭解如何安裝及使用 Cloud Datastore 的用戶端程式庫,請參閱「Cloud Datastore 用戶端程式庫」一文。詳情請參閱 Cloud Datastore PHP API 參考說明文件

如要向 Cloud Datastore 進行驗證,請設定應用程式預設憑證。 詳情請參閱「為本機開發環境設定驗證」。

/**
 * Update two entities in a transaction.
 *
 * @param string $fromKeyId
 * @param string $toKeyId
 * @param int $amount
 * @param string $namespaceId
 */
function transfer_funds(
    string $fromKeyId,
    string $toKeyId,
    int $amount,
    string $namespaceId = null
) {
    $datastore = new DatastoreClient(['namespaceId' => $namespaceId]);
    $transaction = $datastore->transaction();
    $fromKey = $datastore->key('Account', $fromKeyId);
    $toKey = $datastore->key('Account', $toKeyId);
    // The option 'sort' is important here, otherwise the order of the result
    // might be different from the order of the keys.
    $result = $transaction->lookupBatch([$fromKey, $toKey], ['sort' => true]);
    if (count($result['found']) != 2) {
        $transaction->rollback();
    }
    $fromAccount = $result['found'][0];
    $toAccount = $result['found'][1];
    $fromAccount['balance'] -= $amount;
    $toAccount['balance'] += $amount;
    $transaction->updateBatch([$fromAccount, $toAccount]);
    $transaction->commit();
}

Python

如要瞭解如何安裝及使用 Cloud Datastore 的用戶端程式庫,請參閱「Cloud Datastore 用戶端程式庫」一文。詳情請參閱 Cloud Datastore Python API 參考說明文件

如要向 Cloud Datastore 進行驗證,請設定應用程式預設憑證。 詳情請參閱「為本機開發環境設定驗證」。

from google.cloud import datastore

# For help authenticating your client, visit
# https://cloud.google.com/docs/authentication/getting-started
client = datastore.Client()

def transfer_funds(client, from_key, to_key, amount):
    with client.transaction():
        from_account = client.get(from_key)
        to_account = client.get(to_key)

        from_account["balance"] -= amount
        to_account["balance"] += amount

        client.put_multi([from_account, to_account])

Ruby

如要瞭解如何安裝及使用 Cloud Datastore 的用戶端程式庫,請參閱「Cloud Datastore 用戶端程式庫」一文。詳情請參閱 Cloud Datastore Ruby API 參考說明文件

如要向 Cloud Datastore 進行驗證,請設定應用程式預設憑證。 詳情請參閱「為本機開發環境設定驗證」。

def transfer_funds from_key, to_key, amount
  datastore.transaction do |tx|
    from = tx.find from_key
    from["balance"] -= amount
    to = tx.find to_key
    to["balance"] += amount
    tx.save from, to
  end
end

請注意,為了讓範例保持精簡,我們有時會省略交易失敗時會進行的 rollback。在實際執行的程式碼中,請務必確認每項交易是否已明確修訂或復原。

在交易中可執行的操作

交易中的所有 Datastore 作業都可在最多 25 個實體群組上運作。這些操作包括使用祖系查詢實體、使用鍵擷取實體、更新實體以及刪除實體。

當兩個或多項交易同時嘗試修改一或多個共用實體群組中的實體時,只有第一個提出變更的交易會成功,其他則會在提出時失敗。由於這項設計的緣故,使用實體群組會限制您可以對群組中任何實體執行的並行寫入次數。交易開始時,Datastore 會檢查交易中所使用的實體群組上次更新的時間,以便使用開放式並行控制;為實體群組認可交易時,Datastore 會再次檢查交易中所使用的實體群組上次更新的時間,假如該值和首次檢查時不同,則會傳回錯誤訊息。如需實體群組的說明,請參閱「祖系路徑」。

隔離與一致性

在交易之外,Datastore 的隔離等級最接近已修訂的讀取作業;在交易內部,系統則會強制執行可序列化隔離,這代表另一項交易無法並行修改由這項交易讀取或修改的資料。 如要進一步瞭解隔離等級,請參閱維基百科的可序列化隔離說明和交易隔離一文。

在交易中,所有讀取作業都會反映交易開始時 Datastore 的當前一致狀態。在交易開始時,交易內部的查詢一定可看到 Datastore 的一致單一快照。交易實體群組中的實體和索引列會完全更新,因此查詢可傳回完整正確的結果實體組合,而不會如同交易隔離一文所述,在交易之外的查詢中發生誤判和漏判情形。

此一致性的快照檢視也擴充至交易內部的寫入後的讀取。與大部分資料庫不同,Datastore 交易內部的查詢和獲取「不會」看到先前在該交易中寫入的結果,尤其如果實體在交易內經過修改或刪除,查詢或將傳回交易開始時的「原始」版實體;如果當時該實體尚不存在,則不傳回任何實體。

交易用途

交易的其中一種用途是將實體目前的屬性值變更為較新的值。在上述 transferFunds 範例中,從一個帳戶領取金額然後轉移到另一個帳戶,會更新兩個實體的屬性值。Datastore API 不會自動重試交易,但您可以自行新增邏輯以便進行重試;假如其他要求同時對同一實體進行更新而導致衝突,您便可藉此予以解決。

C#

如要瞭解如何安裝及使用 Cloud Datastore 的用戶端程式庫,請參閱「Cloud Datastore 用戶端程式庫」一文。詳情請參閱 Cloud Datastore C# API 參考說明文件

如要向 Cloud Datastore 進行驗證,請設定應用程式預設憑證。 詳情請參閱「為本機開發環境設定驗證」。

/// <summary>
/// Retry the action when a Grpc.Core.RpcException is thrown.
/// </summary>
private T RetryRpc<T>(Func<T> action)
{
    List<Grpc.Core.RpcException> exceptions = null;
    var delayMs = _retryDelayMs;
    for (int tryCount = 0; tryCount < _retryCount; ++tryCount)
    {
        try
        {
            return action();
        }
        catch (Grpc.Core.RpcException e)
        {
            if (exceptions == null)
                exceptions = new List<Grpc.Core.RpcException>();
            exceptions.Add(e);
        }
        System.Threading.Thread.Sleep(delayMs);
        delayMs *= 2;  // Exponential back-off.
    }
    throw new AggregateException(exceptions);
}

private void RetryRpc(Action action)
{
    RetryRpc(() => { action(); return 0; });
}

[Fact]
public void TestTransactionalRetry()
{
    int tryCount = 0;
    var keys = UpsertBalances();
    RetryRpc(() =>
    {
        using (var transaction = _db.BeginTransaction())
        {
            TransferFunds(keys[0], keys[1], 10, transaction);
            // Insert a conflicting transaction on the first try.
            if (tryCount++ == 0)
                TransferFunds(keys[1], keys[0], 5);
            transaction.Commit();
        }
    });
    Assert.Equal(2, tryCount);
}

Go

如要瞭解如何安裝及使用 Cloud Datastore 的用戶端程式庫,請參閱「Cloud Datastore 用戶端程式庫」一文。詳情請參閱 Cloud Datastore Go API 參考說明文件

如要向 Cloud Datastore 進行驗證,請設定應用程式預設憑證。 詳情請參閱「為本機開發環境設定驗證」。

type BankAccount struct {
	Balance int
}

const amount = 50
_, err := client.RunInTransaction(ctx, func(tx *datastore.Transaction) error {
	keys := []*datastore.Key{to, from}
	accs := make([]BankAccount, 2)
	if err := tx.GetMulti(keys, accs); err != nil {
		return err
	}
	accs[0].Balance += amount
	accs[1].Balance -= amount
	_, err := tx.PutMulti(keys, accs)
	return err
})

Java

如要瞭解如何安裝及使用 Cloud Datastore 的用戶端程式庫,請參閱「Cloud Datastore 用戶端程式庫」一文。詳情請參閱 Cloud Datastore Java API 參考說明文件

如要向 Cloud Datastore 進行驗證,請設定應用程式預設憑證。 詳情請參閱「為本機開發環境設定驗證」。

int retries = 5;
while (true) {
  try {
    transferFunds(fromKey, toKey, 10);
    break;
  } catch (DatastoreException e) {
    if (retries == 0) {
      throw e;
    }
    --retries;
  }
}
// Retry handling can also be configured and automatically applied using google-cloud-java.

Node.js

如要瞭解如何安裝及使用 Cloud Datastore 的用戶端程式庫,請參閱「Cloud Datastore 用戶端程式庫」一文。詳情請參閱 Cloud Datastore Node.js API 參考說明文件

如要向 Cloud Datastore 進行驗證,請設定應用程式預設憑證。 詳情請參閱「為本機開發環境設定驗證」。

async function transferFundsWithRetry() {
  const maxTries = 5;

  async function tryRequest(currentAttempt, delay) {
    try {
      await transferFunds(fromKey, toKey, 10);
    } catch (err) {
      if (currentAttempt <= maxTries) {
        // Use exponential backoff
        setTimeout(async () => {
          await tryRequest(currentAttempt + 1, delay * 2);
        }, delay);
      }
      throw err;
    }
  }

  await tryRequest(1, 100);
}

PHP

如要瞭解如何安裝及使用 Cloud Datastore 的用戶端程式庫,請參閱「Cloud Datastore 用戶端程式庫」一文。詳情請參閱 Cloud Datastore PHP API 參考說明文件

如要向 Cloud Datastore 進行驗證,請設定應用程式預設憑證。 詳情請參閱「為本機開發環境設定驗證」。

$retries = 5;
for ($i = 0; $i < $retries; $i++) {
    try {
        require_once __DIR__ . '/transfer_funds.php';
        transfer_funds($fromKeyId, $toKeyId, 10, $namespaceId);
    } catch (\Google\Cloud\Core\Exception\ConflictException $e) {
        // if $i >= $retries, the failure is final
        continue;
    }
    // Succeeded!
    break;
}

Python

如要瞭解如何安裝及使用 Cloud Datastore 的用戶端程式庫,請參閱「Cloud Datastore 用戶端程式庫」一文。詳情請參閱 Cloud Datastore Python API 參考說明文件

如要向 Cloud Datastore 進行驗證,請設定應用程式預設憑證。 詳情請參閱「為本機開發環境設定驗證」。

from google.cloud import datastore

# For help authenticating your client, visit
# https://cloud.google.com/docs/authentication/getting-started
client = datastore.Client()

import google.cloud.exceptions

for _ in range(5):
    try:
        transfer_funds(client, account1.key, account2.key, 50)
        break
    except google.cloud.exceptions.Conflict:
        continue
else:
    print("Transaction failed.")

Ruby

如要瞭解如何安裝及使用 Cloud Datastore 的用戶端程式庫,請參閱「Cloud Datastore 用戶端程式庫」一文。詳情請參閱 Cloud Datastore Ruby API 參考說明文件

如要向 Cloud Datastore 進行驗證,請設定應用程式預設憑證。 詳情請參閱「為本機開發環境設定驗證」。

(1..5).each do |i|
  begin
    return transfer_funds from_key, to_key, amount
  rescue Google::Cloud::Error => e
    raise e if i == 5
  end
end

這需要使用交易,因為在此程式碼擷取物件之後,其他使用者可能會在系統尚未儲存已修改物件的情況下更新實體中的 balance 值。如果沒有交易,則使用者的要求將採用其他使用者更新之前的 balance 值,而儲存也將覆寫新的值。但是藉由交易,應用程式將得知其他使用者的更新。

交易的另一個常見用途是擷取具有指定鍵的實體,或是在該鍵不存在的狀態下予以建立。本範例是以建立實體一節的 TaskList 範例做為基礎:

C#

如要瞭解如何安裝及使用 Cloud Datastore 的用戶端程式庫,請參閱「Cloud Datastore 用戶端程式庫」一文。詳情請參閱 Cloud Datastore C# API 參考說明文件

如要向 Cloud Datastore 進行驗證,請設定應用程式預設憑證。 詳情請參閱「為本機開發環境設定驗證」。

Entity task;
using (var transaction = _db.BeginTransaction())
{
    task = transaction.Lookup(_sampleTask.Key);
    if (task == null)
    {
        transaction.Insert(_sampleTask);
        transaction.Commit();
    }
}

Go

如要瞭解如何安裝及使用 Cloud Datastore 的用戶端程式庫,請參閱「Cloud Datastore 用戶端程式庫」一文。詳情請參閱 Cloud Datastore Go API 參考說明文件

如要向 Cloud Datastore 進行驗證,請設定應用程式預設憑證。 詳情請參閱「為本機開發環境設定驗證」。

_, err := client.RunInTransaction(ctx, func(tx *datastore.Transaction) error {
	var task Task
	if err := tx.Get(key, &task); err != datastore.ErrNoSuchEntity {
		return err
	}
	_, err := tx.Put(key, &Task{
		Category:    "Personal",
		Done:        false,
		Priority:    4,
		Description: "Learn Cloud Datastore",
	})
	return err
})

Java

如要瞭解如何安裝及使用 Cloud Datastore 的用戶端程式庫,請參閱「Cloud Datastore 用戶端程式庫」一文。詳情請參閱 Cloud Datastore Java API 參考說明文件

如要向 Cloud Datastore 進行驗證,請設定應用程式預設憑證。 詳情請參閱「為本機開發環境設定驗證」。

Entity task;
Transaction txn = datastore.newTransaction();
try {
  task = txn.get(taskKey);
  if (task == null) {
    task = Entity.newBuilder(taskKey).build();
    txn.put(task);
    txn.commit();
  }
} finally {
  if (txn.isActive()) {
    txn.rollback();
  }
}

Node.js

如要瞭解如何安裝及使用 Cloud Datastore 的用戶端程式庫,請參閱「Cloud Datastore 用戶端程式庫」一文。詳情請參閱 Cloud Datastore Node.js API 參考說明文件

如要向 Cloud Datastore 進行驗證,請設定應用程式預設憑證。 詳情請參閱「為本機開發環境設定驗證」。

async function getOrCreate(taskKey, taskData) {
  const taskEntity = {
    key: taskKey,
    data: taskData,
  };
  const transaction = datastore.transaction();

  try {
    await transaction.run();
    const [task] = await transaction.get(taskKey);
    if (task) {
      // The task entity already exists.
      await transaction.rollback();
    } else {
      // Create the task entity.
      transaction.save(taskEntity);
      await transaction.commit();
    }
    return taskEntity;
  } catch (err) {
    await transaction.rollback();
  }
}

PHP

如要瞭解如何安裝及使用 Cloud Datastore 的用戶端程式庫,請參閱「Cloud Datastore 用戶端程式庫」一文。詳情請參閱 Cloud Datastore PHP API 參考說明文件

如要向 Cloud Datastore 進行驗證,請設定應用程式預設憑證。 詳情請參閱「為本機開發環境設定驗證」。

$transaction = $datastore->transaction();
$entity = $transaction->lookup($task->key());
if ($entity === null) {
    $entity = $transaction->insert($task);
    $transaction->commit();
}

Python

如要瞭解如何安裝及使用 Cloud Datastore 的用戶端程式庫,請參閱「Cloud Datastore 用戶端程式庫」一文。詳情請參閱 Cloud Datastore Python API 參考說明文件

如要向 Cloud Datastore 進行驗證,請設定應用程式預設憑證。 詳情請參閱「為本機開發環境設定驗證」。

from google.cloud import datastore

# For help authenticating your client, visit
# https://cloud.google.com/docs/authentication/getting-started
client = datastore.Client()

import datetime

with client.transaction():
    key = client.key(
        "Task", datetime.datetime.now(tz=datetime.timezone.utc).isoformat()
    )

    task = client.get(key)

    if not task:
        task = datastore.Entity(key)
        task.update({"description": "Example task"})
        client.put(task)

    return task

Ruby

如要瞭解如何安裝及使用 Cloud Datastore 的用戶端程式庫,請參閱「Cloud Datastore 用戶端程式庫」一文。詳情請參閱 Cloud Datastore Ruby API 參考說明文件

如要向 Cloud Datastore 進行驗證,請設定應用程式預設憑證。 詳情請參閱「為本機開發環境設定驗證」。

task = nil
datastore.transaction do |tx|
  task = tx.find task_key
  if task.nil?
    task = datastore.entity task_key do |t|
      t["category"] = "Personal"
      t["done"] = false
      t["priority"] = 4
      t["description"] = "Learn Cloud Datastore"
    end
    tx.save task
  end
end

和先前一樣,如要處理另一個使用者嘗試建立或更新具有相同字串 ID 實體的情況,就必須使用交易。如果交易不存在,而且上述這個實體不存在,當兩位使用者嘗試建立這個實體時,第二位使用者將在不知情的狀況下,覆寫掉第一位使用者所建立的實體。

當交易失敗時,您可以讓應用程式重試交易直到成功為止,也可以將交易傳播至應用程式的使用者介面層級,讓使用者處理錯誤。您不必為每一項交易建立重試迴圈。

最後,您可以使用交易來讀取 Datastore 的一致快照。當需要透過多個讀取作業轉譯網頁,或是匯出必須是一致的資料時,這項功能相當有用。由於這種交易不執行寫入作業,所以通常稱為「唯讀」交易。單一群組唯讀交易絕不會因並行修改而失敗,因此您不必在失敗時重試。不過,多實體群組交易可能會因並行修改而失敗,所以必須進行重試。

C#

如要瞭解如何安裝及使用 Cloud Datastore 的用戶端程式庫,請參閱「Cloud Datastore 用戶端程式庫」一文。詳情請參閱 Cloud Datastore C# API 參考說明文件

如要向 Cloud Datastore 進行驗證,請設定應用程式預設憑證。 詳情請參閱「為本機開發環境設定驗證」。

Entity taskList;
IReadOnlyList<Entity> tasks;
using (var transaction = _db.BeginTransaction(TransactionOptions.CreateReadOnly()))
{
    taskList = transaction.Lookup(taskListKey);
    var query = new Query("Task")
    {
        Filter = Filter.HasAncestor(taskListKey)
    };
    tasks = transaction.RunQuery(query).Entities;
    transaction.Commit();
}

Go

如要瞭解如何安裝及使用 Cloud Datastore 的用戶端程式庫,請參閱「Cloud Datastore 用戶端程式庫」一文。詳情請參閱 Cloud Datastore Go API 參考說明文件

如要向 Cloud Datastore 進行驗證,請設定應用程式預設憑證。 詳情請參閱「為本機開發環境設定驗證」。

tx, err := client.NewTransaction(ctx, datastore.ReadOnly)
if err != nil {
	log.Fatalf("client.NewTransaction: %v", err)
}
defer tx.Rollback() // Transaction only used for read.

ancestor := datastore.NameKey("TaskList", "default", nil)
query := datastore.NewQuery("Task").Ancestor(ancestor).Transaction(tx)
var tasks []Task
_, err = client.GetAll(ctx, query, &tasks)

Java

如要瞭解如何安裝及使用 Cloud Datastore 的用戶端程式庫,請參閱「Cloud Datastore 用戶端程式庫」一文。詳情請參閱 Cloud Datastore Java API 參考說明文件

如要向 Cloud Datastore 進行驗證,請設定應用程式預設憑證。 詳情請參閱「為本機開發環境設定驗證」。

Entity taskList;
QueryResults<Entity> tasks;
Transaction txn =
    datastore.newTransaction(
        TransactionOptions.newBuilder().setReadOnly(ReadOnly.newBuilder().build()).build());
try {
  taskList = txn.get(taskListKey);
  Query<Entity> query =
      Query.newEntityQueryBuilder()
          .setKind("Task")
          .setFilter(PropertyFilter.hasAncestor(taskListKey))
          .build();
  tasks = txn.run(query);
  txn.commit();
} finally {
  if (txn.isActive()) {
    txn.rollback();
  }
}

Node.js

如要瞭解如何安裝及使用 Cloud Datastore 的用戶端程式庫,請參閱「Cloud Datastore 用戶端程式庫」一文。詳情請參閱 Cloud Datastore Node.js API 參考說明文件

如要向 Cloud Datastore 進行驗證,請設定應用程式預設憑證。 詳情請參閱「為本機開發環境設定驗證」。

async function getTaskListEntities() {
  const transaction = datastore.transaction({readOnly: true});
  try {
    const taskListKey = datastore.key(['TaskList', 'default']);

    await transaction.run();
    const [taskList] = await transaction.get(taskListKey);
    const query = datastore.createQuery('Task').hasAncestor(taskListKey);
    const [taskListEntities] = await transaction.runQuery(query);
    await transaction.commit();
    return [taskList, taskListEntities];
  } catch (err) {
    await transaction.rollback();
  }
}

PHP

如要瞭解如何安裝及使用 Cloud Datastore 的用戶端程式庫,請參閱「Cloud Datastore 用戶端程式庫」一文。詳情請參閱 Cloud Datastore PHP API 參考說明文件

如要向 Cloud Datastore 進行驗證,請設定應用程式預設憑證。 詳情請參閱「為本機開發環境設定驗證」。

$transaction = $datastore->readOnlyTransaction();
$taskListKey = $datastore->key('TaskList', 'default');
$query = $datastore->query()
    ->kind('Task')
    ->hasAncestor($taskListKey);
$result = $transaction->runQuery($query);
$taskListEntities = [];
$num = 0;
/* @var Entity $task */
foreach ($result as $task) {
    $taskListEntities[] = $task;
    $num += 1;
}

Python

如要瞭解如何安裝及使用 Cloud Datastore 的用戶端程式庫,請參閱「Cloud Datastore 用戶端程式庫」一文。詳情請參閱 Cloud Datastore Python API 參考說明文件

如要向 Cloud Datastore 進行驗證,請設定應用程式預設憑證。 詳情請參閱「為本機開發環境設定驗證」。

from google.cloud import datastore

# For help authenticating your client, visit
# https://cloud.google.com/docs/authentication/getting-started
client = datastore.Client()

with client.transaction(read_only=True):
    task_list_key = client.key("TaskList", "default")

    task_list = client.get(task_list_key)

    query = client.query(kind="Task", ancestor=task_list_key)
    tasks_in_list = list(query.fetch())

    return task_list, tasks_in_list

Ruby

如要瞭解如何安裝及使用 Cloud Datastore 的用戶端程式庫,請參閱「Cloud Datastore 用戶端程式庫」一文。詳情請參閱 Cloud Datastore Ruby API 參考說明文件

如要向 Cloud Datastore 進行驗證,請設定應用程式預設憑證。 詳情請參閱「為本機開發環境設定驗證」。

# task_list_name = "default"
task_list_key = datastore.key "TaskList", task_list_name
datastore.read_only_transaction do |tx|
  task_list = tx.find task_list_key
  query = datastore.query("Task").ancestor(task_list)
  tasks_in_list = tx.run query
end

交易和實體群組

實體群組是透過祖系連接至共同根元素的一組實體。將資料歸納為實體群組,即可限制執行的交易類型:

  • 一項交易所存取的所有資料,最多只能存在於 25 個實體群組中。
  • 如果您想在交易中使用查詢,必須將資料歸納成實體群組,才可指定能夠比對出正確資料的祖系篩選條件。
  • 單一實體群組的寫入總處理量大約是每秒一次交易。之所以會有這項限制,原因在於 Datastore 會針對橫跨大範圍地理區域的每個實體執行免主機的同步複製作業,以利發揮高度的可靠性和容錯能力。

在許多應用程式中,取得不相關資料的概觀時,可以使用最終一致性 (即跨越多個實體群組的非祖先查詢,有時可能會傳回稍微過時的資料),然後在查看或編輯一組高度相關的資料時,使用強烈一致性 (祖先查詢或單一實體的 lookup)。在此類應用程式中,針對各組高度相關的資料使用獨立實體群組,通常會有不錯的效果。 詳情請參閱「資料一致性」。

後續步驟