交易

「交易」是在一或多個實體上應用的一組作業。每次交易皆保證具有單元性,這代表交易絕不會部分完成。換句話說,交易中的操作不是全部完成,就是全部不予進行。

使用交易

交易會在 270 秒後到期,或閒置 60 秒後到期。

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

  • 在同一個實體上嘗試進行太多並行修改。
  • 交易超過資源限制。
  • Datastore 模式資料庫遭遇內部錯誤。

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

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

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

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

C#

如要瞭解如何安裝及使用 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 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 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 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 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 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 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。在實際執行的程式碼中,請務必確認每項交易是否已明確修訂或復原。

在交易中可執行的操作

交易可查詢任意數量的實體。交易的大小上限為 10 MiB。您可以使用讀寫交易或唯讀交易。

隔離與一致性

Datastore 模式資料庫會強制執行「可序列化隔離」。您無法以並行的方式修改由交易讀取或修改的資料。

交易中的查詢會看到資料庫狀態的一致快照。此快照一定包含交易開始之前完成的所有交易和寫入作業的影響。

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

在交易之外,也會對查詢進行可序列化隔離。

並行模式

Datastore 模式的 Firestore 支援三種並行模式。並行模式是資料庫設定,可決定並行交易的互動方式。您可以選取下列任一並行模式:

  • 悲觀

    讀寫交易會使用讀取/寫入鎖定來強制執行隔離和可序列化作業。當兩筆以上的並行讀寫交易讀取或寫入相同資料時,其中一筆交易持有的鎖定可能會延遲其他交易。如果交易不需要任何寫入作業,您可以使用唯讀交易,提升效能並避免與其他交易發生爭用情形。唯讀交易不需要任何鎖定。

    Datastore 模式的 Firestore 資料庫預設使用悲觀並行模式。

  • 樂觀

    當兩個以上的並行讀寫交易讀取或寫入相同資料時,只有第一個提出變更的交易會成功,執行寫入作業的其他交易會在提交時失敗。

  • 樂觀 (含實體群組)

    只有在應用程式依賴舊版 Cloud Datastore 的實體群組交易語意時,才使用這個並行模式。這個並行模式會對交易施加額外限制:

    • 交易受限於 25 個實體群組。
    • 寫入實體群組的速度限制為每秒 1 個。
    • 交易中的查詢必須是祖系查詢。

    如要移除 OPTIMISTIC_WITH_ENTITY_GROUPS 查詢、交易和寫入輸送量限制,請將專案的並行模式變更為「樂觀」。為確保這項變更與專案相容,請按照下列步驟操作:

    1. 在 Datastore 模式的 Firestore 中建立測試專案。

    2. 將測試專案的並行模式變更為 OPTIMISTIC。發出 HTTP PATCH 要求,如下所示。

    3. 在測試專案中執行測試,確保工作負載在沒有實體群組的情況下,仍能正常運作。

    4. 將主要專案的並行模式OPTIMISTIC_WITH_ENTITY_GROUPS 變更為 OPTIMISTIC

查看並行模式

使用 Firestore projects.databases REST 資源,查看資料庫的並行模式:

curl -X GET -H "Authorization: Bearer "$(gcloud auth print-access-token) \
"https://firestore.googleapis.com/v1/projects/PROJECT_ID/databases"

變更並行模式

如要變更資料庫的並行模式,請將 PATCH 要求傳送至 Firestore projects.databases REST 資源:

curl --request PATCH \
--header "Authorization: Bearer "$(gcloud auth print-access-token) \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{"concurrencyMode":"CONCURRENCY_MODE"}' \
"https://firestore.googleapis.com/v1/projects/PROJECT_ID/databases/(default)?updateMask=concurrencyMode"

其中:

  • CONCURRENCY_MODEPESSIMISTICOPTIMISTICOPTIMISTIC_WITH_ENTITY_GROUPS
  • PROJECT_ID 是 Google Cloud 專案 ID。

交易用途

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

C#

如要瞭解如何安裝及使用 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 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 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 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 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 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 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 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 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 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 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 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 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 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 實體的情況,就必須使用交易。如果交易不存在,而且上述這個實體不存在,當兩位使用者嘗試建立這個實體時,第二位使用者將在不知情的狀況下,覆寫掉第一位使用者所建立的實體。

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

唯讀交易

最後,您可以使用交易讀取資料庫的一致快照。當您需要透過多個讀取作業轉譯網頁,或是匯出必須是一致的資料時,這項功能相當有用。您可以針對這些情況建立唯讀交易。

唯讀交易無法修改實體,但作為交換,這種交易不會與其他任何交易發生爭用,也不需要重試。如果您在一般讀寫交易中僅執行讀取作業,則該交易可能會與修改相同資料的交易發生爭用。

C#

如要瞭解如何安裝及使用 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 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 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 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 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 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 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

後續步驟