טרנזקציות ב-Cloud Datastore

עסקה היא קבוצה של פעולות Datastore על ישות אחת או יותר, ב-25 קבוצות ישויות לכל היותר. כל עסקה מובטחת להיות אטומית, כלומר העסקאות אף פעם לא מיושמות באופן חלקי. כל הפעולות בעסקה מוחלות או שאף אחת מהן לא מוחלת.

שימוש בעסקאות

המשך המקסימלי של העסקאות הוא 270 שניות, עם זמן סיום של 10 שניות אחרי 30 שניות של חוסר פעילות.

פעולה עלולה להיכשל במקרים הבאים:

  • נעשה ניסיון לבצע יותר מדי שינויים בו-זמנית באותה קבוצת ישויות.
  • העסקה חורגת ממגבלת משאבים.
  • מערכת Datastore נתקלת בשגיאה פנימית.

בכל המקרים האלה, ה-API של Datastore מחזיר שגיאה.

עסקאות הן תכונה אופציונלית של Datastore. לא חייבים להשתמש בעסקאות כדי לבצע פעולות ב-Datastore.

אפליקציה יכולה להריץ קבוצה של הצהרות ופעולות Datastore בעסקה אחת, כך שאם הצהרה או פעולה כלשהי מעלות חריגה, אף אחת מהפעולות של Datastore בקבוצה לא מוחלת. האפליקציה מגדירה את הפעולות שיש לבצע בעסקה.

בקטע הקוד הבא אפשר לראות איך לבצע טרנזקציה באמצעות Datastore API. העברת כסף מחשבון אחד לחשבון אחר.

C#

מידע על התקנת ספריית הלקוח של Cloud Datastore ושימוש בה מופיע במאמר ספריות הלקוח של Cloud Datastore. מידע נוסף מופיע במאמרי העזרה של Cloud Datastore C# API.

כדי לבצע אימות ב-Cloud Datastore, צריך להגדיר את Application Default Credentials. מידע נוסף זמין במאמר הגדרת אימות לסביבת פיתוח מקומית.

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, צריך להגדיר את Application Default Credentials. מידע נוסף זמין במאמר הגדרת אימות לסביבת פיתוח מקומית.

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, צריך להגדיר את Application Default Credentials. מידע נוסף זמין במאמר הגדרת אימות לסביבת פיתוח מקומית.

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, צריך להגדיר את Application Default Credentials. מידע נוסף זמין במאמר הגדרת אימות לסביבת פיתוח מקומית.

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, צריך להגדיר את Application Default Credentials. מידע נוסף זמין במאמר הגדרת אימות לסביבת פיתוח מקומית.

/**
 * 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, צריך להגדיר את Application Default Credentials. מידע נוסף זמין במאמר הגדרת אימות לסביבת פיתוח מקומית.

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, צריך להגדיר את Application Default Credentials. מידע נוסף זמין במאמר הגדרת אימות לסביבת פיתוח מקומית.

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 משתמש בבקרת מקבילות אופטימית על ידי בדיקת זמן העדכון האחרון של קבוצות הישויות שמשמשות בטרנזקציה. כשמבצעים פעולת אישור (commit) של טרנזקציה עבור קבוצות הישויות, Datastore בודק שוב את זמן העדכון האחרון של קבוצות הישויות שנעשה בהן שימוש בטרנזקציה. אם הוא השתנה מאז הבדיקה הראשונית שלנו, תוחזר שגיאה. הסבר על קבוצות ישויות זמין במאמר נתיבי ישויות אב.

בידוד ועקביות

מחוץ לעסקאות, רמת הבידוד של Datastore הכי קרובה ל-read committed. בתוך טרנזקציות, נאכף בידוד שניתן לסדר. המשמעות היא שעסקה אחרת לא יכולה לשנות בו-זמנית את הנתונים שנקראים או משתנים על ידי העסקה הזו. מידע נוסף על רמות הבידוד זמין במאמר בידוד טרנזקציות ובדף הוויקי בנושא בידוד ניתן לסריאליזציה.

בטרנזקציה, כל פעולות הקריאה משקפות את המצב העדכני והעקבי של Datastore בזמן שהטרנזקציה התחילה. מובטח ששאילתות וחיפושים בתוך טרנזקציה יראו תמונה עקבית אחת של Datastore, נכון לתחילת הטרנזקציה. הישויות ושורות האינדקס בקבוצות הישויות של העסקה מתעדכנות באופן מלא, כך שהשאילתות מחזירות את קבוצת הישויות המלאה והנכונה של התוצאות, ללא התוצאות החיוביות השגויות או התוצאות השליליות השגויות שמתוארות בבידוד עסקאות, שיכולות להתרחש בשאילתות מחוץ לעסקאות.

תצוגת התמונה העקבית הזו חלה גם על קריאות אחרי כתיבות בתוך טרנזקציות. בניגוד לרוב מסדי הנתונים, שאילתות ופעולות get בתוך טרנזקציה של Datastore לא רואות את התוצאות של פעולות כתיבה קודמות בתוך אותה טרנזקציה. באופן ספציפי, אם ישות משתנה או נמחקת במהלך טרנזקציה, שאילתה או חיפוש מחזירים את הגרסה המקורית של הישות כפי שהיא הייתה בתחילת הטרנזקציה, או שלא מחזירים כלום אם הישות לא הייתה קיימת באותו זמן.

שימושים בעסקאות

אחד השימושים בעסקאות הוא עדכון ישות עם ערך מאפיין חדש ביחס לערך הנוכחי שלה. בדוגמה transferFunds שלמעלה, הפעולה הזו מתבצעת עבור שתי ישויות: משיכת כסף מחשבון אחד והעברה שלו לחשבון אחר. ממשק Datastore API לא מנסה לבצע שוב טרנזקציות באופן אוטומטי, אבל אתם יכולים להוסיף לוגיקה משלכם כדי לנסות לבצע אותן שוב. למשל, כדי לטפל בקונפליקטים כשבקשה אחרת מעדכנת את אותה ישות באותו הזמן.

C#

מידע על התקנת ספריית הלקוח של Cloud Datastore ושימוש בה מופיע במאמר ספריות הלקוח של Cloud Datastore. מידע נוסף מופיע במאמרי העזרה של Cloud Datastore C# API.

כדי לבצע אימות ב-Cloud Datastore, צריך להגדיר את Application Default Credentials. מידע נוסף זמין במאמר הגדרת אימות לסביבת פיתוח מקומית.

/// <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, צריך להגדיר את Application Default Credentials. מידע נוסף זמין במאמר הגדרת אימות לסביבת פיתוח מקומית.

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, צריך להגדיר את Application Default Credentials. מידע נוסף זמין במאמר הגדרת אימות לסביבת פיתוח מקומית.

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, צריך להגדיר את Application Default Credentials. מידע נוסף זמין במאמר הגדרת אימות לסביבת פיתוח מקומית.

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, צריך להגדיר את Application Default Credentials. מידע נוסף זמין במאמר הגדרת אימות לסביבת פיתוח מקומית.

$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, צריך להגדיר את Application Default Credentials. מידע נוסף זמין במאמר הגדרת אימות לסביבת פיתוח מקומית.

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, צריך להגדיר את Application Default Credentials. מידע נוסף זמין במאמר הגדרת אימות לסביבת פיתוח מקומית.

(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, צריך להגדיר את Application Default Credentials. מידע נוסף זמין במאמר הגדרת אימות לסביבת פיתוח מקומית.

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, צריך להגדיר את Application Default Credentials. מידע נוסף זמין במאמר הגדרת אימות לסביבת פיתוח מקומית.

_, 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, צריך להגדיר את Application Default Credentials. מידע נוסף זמין במאמר הגדרת אימות לסביבת פיתוח מקומית.

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, צריך להגדיר את Application Default Credentials. מידע נוסף זמין במאמר הגדרת אימות לסביבת פיתוח מקומית.

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, צריך להגדיר את Application Default Credentials. מידע נוסף זמין במאמר הגדרת אימות לסביבת פיתוח מקומית.

$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, צריך להגדיר את Application Default Credentials. מידע נוסף זמין במאמר הגדרת אימות לסביבת פיתוח מקומית.

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, צריך להגדיר את Application Default Credentials. מידע נוסף זמין במאמר הגדרת אימות לסביבת פיתוח מקומית.

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

כמו קודם, נדרשת טרנזקציה כדי לטפל במקרה שבו משתמש אחר מנסה ליצור או לעדכן ישות עם אותו מזהה מחרוזת. אם אין עסקה, והישות לא קיימת ושני משתמשים מנסים ליצור אותה, המשתמש השני דורס את המשתמש הראשון בלי לדעת שזה קרה.

אם העסקה נכשלת, אתם יכולים להגדיר שהאפליקציה תנסה שוב לבצע את העסקה עד שהיא תצליח, או לאפשר למשתמשים לטפל בשגיאה על ידי העברתה לרמת ממשק המשתמש של האפליקציה. לא צריך ליצור לולאת ניסיון חוזר סביב כל עסקה.

לבסוף, אפשר להשתמש בעסקה כדי לקרוא תמונת מצב עקבית של Datastore. האפשרות הזו יכולה להיות שימושית כשצריך לבצע כמה קריאות כדי לעבד דף או לייצא נתונים שצריכים להיות עקביים. עסקאות מהסוג הזה נקראות לעיתים קרובות עסקאות לקריאה בלבד, כי הן לא מבצעות פעולות כתיבה. עסקאות של קבוצה אחת עם הרשאת קריאה בלבד אף פעם לא נכשלות בגלל שינויים שנעשים במקביל, כך שאין צורך להטמיע ניסיונות חוזרים במקרה של כשל. עם זאת, יכול להיות שעסקאות של קבוצות עם כמה ישויות ייכשלו בגלל שינויים שנעשים במקביל, ולכן צריך להגדיר ניסיונות חוזרים לעסקאות כאלה.

C#

מידע על התקנת ספריית הלקוח של Cloud Datastore ושימוש בה מופיע במאמר ספריות הלקוח של Cloud Datastore. מידע נוסף מופיע במאמרי העזרה של Cloud Datastore C# API.

כדי לבצע אימות ב-Cloud Datastore, צריך להגדיר את Application Default Credentials. מידע נוסף זמין במאמר הגדרת אימות לסביבת פיתוח מקומית.

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, צריך להגדיר את Application Default Credentials. מידע נוסף זמין במאמר הגדרת אימות לסביבת פיתוח מקומית.

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, צריך להגדיר את Application Default Credentials. מידע נוסף זמין במאמר הגדרת אימות לסביבת פיתוח מקומית.

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, צריך להגדיר את Application Default Credentials. מידע נוסף זמין במאמר הגדרת אימות לסביבת פיתוח מקומית.

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, צריך להגדיר את Application Default Credentials. מידע נוסף זמין במאמר הגדרת אימות לסביבת פיתוח מקומית.

$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, צריך להגדיר את Application Default Credentials. מידע נוסף זמין במאמר הגדרת אימות לסביבת פיתוח מקומית.

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, צריך להגדיר את Application Default Credentials. מידע נוסף זמין במאמר הגדרת אימות לסביבת פיתוח מקומית.

# 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 של ישות אחת) כשרוצים להציג או לערוך קבוצה אחת של נתונים קשורים מאוד. במקרים כאלה, בדרך כלל מומלץ להשתמש בקבוצת ישויות נפרדת לכל קבוצה של נתונים שקשורים זה לזה באופן הדוק. מידע נוסף זמין במאמר עקביות נתונים.

המאמרים הבאים