Transactions

Une transaction est un ensemble d'opérations sur une ou plusieurs entités. Chaque transaction est atomique, ce qui signifie que les transactions ne sont jamais partiellement appliquées. Toutes les opérations de la transaction sont appliquées, ou aucune d'entre elles ne l'est.

Utiliser des transactions

Les transactions expirent au bout de 270 secondes ou si elles sont inactives pendant 60 secondes.

Une opération peut échouer lorsque :

  • trop de modifications simultanées s'effectuent sur le même groupe d'entités ;
  • la transaction dépasse une limite de ressources ;
  • la base de données en mode Datastore rencontre une erreur interne.

Dans tous les cas précédents, l'API Cloud Datastore renvoie une erreur.

Les transactions sont une fonctionnalité facultative. Vous n'êtes pas obligé d'utiliser des transactions pour effectuer des opérations de base de données.

Une application peut exécuter un ensemble d'instructions et d'opérations au sein d'une même transaction. Ainsi, si une instruction ou une opération génère une exception, aucune des opérations de base de données de l'ensemble n'est appliquée. L'application définit les actions à effectuer dans la transaction.

L'extrait suivant indique comment effectuer une transaction. Il transfère de l'argent d'un compte à un autre.

C#

Pour savoir comment installer et utiliser la bibliothèque cliente pour Cloud Datastore, consultez la page Bibliothèques clientes Cloud Datastore. Pour en savoir plus, consultez les API C# Cloud Datastore documentation de référence.

Pour vous authentifier auprès de Cloud Datastore, configurez les identifiants par défaut de l'application. Pour en savoir plus, consultez Configurer l'authentification pour un environnement de développement local.

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

Pour savoir comment installer et utiliser la bibliothèque cliente pour Cloud Datastore, consultez Bibliothèques clientes Cloud Datastore. Pour en savoir plus, consultez la documentation de référence de l'API Cloud Datastore Go.

Pour vous authentifier auprès de Cloud Datastore, configurez le service Identifiants par défaut de l'application. Pour en savoir plus, consultez Configurer l'authentification pour un environnement de développement local.

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

Pour savoir comment installer et utiliser la bibliothèque cliente pour Cloud Datastore, consultez Bibliothèques clientes Cloud Datastore. Pour en savoir plus, consultez les API Java Cloud Datastore documentation de référence.

Pour vous authentifier auprès de Cloud Datastore, configurez les identifiants par défaut de l'application. Pour en savoir plus, consultez Configurer l'authentification pour un environnement de développement local.

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

Pour savoir comment installer et utiliser la bibliothèque cliente pour Cloud Datastore, consultez Bibliothèques clientes Cloud Datastore. Pour en savoir plus, consultez les API Node.js Cloud Datastore documentation de référence.

Pour vous authentifier auprès de Cloud Datastore, configurez les identifiants par défaut de l'application. Pour en savoir plus, consultez Configurer l'authentification pour un environnement de développement local.

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

Pour savoir comment installer et utiliser la bibliothèque cliente pour Cloud Datastore, consultez Bibliothèques clientes Cloud Datastore. Pour en savoir plus, consultez les API PHP Cloud Datastore documentation de référence.

Pour vous authentifier auprès de Cloud Datastore, configurez les identifiants par défaut de l'application. Pour en savoir plus, consultez Configurer l'authentification pour un environnement de développement local.

/**
 * 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

Pour savoir comment installer et utiliser la bibliothèque cliente pour Cloud Datastore, consultez Bibliothèques clientes Cloud Datastore. Pour en savoir plus, consultez les API Python Cloud Datastore documentation de référence.

Pour vous authentifier auprès de Cloud Datastore, configurez les identifiants par défaut de l'application. Pour en savoir plus, consultez Configurer l'authentification pour un environnement de développement local.

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

Pour savoir comment installer et utiliser la bibliothèque cliente pour Cloud Datastore, consultez Bibliothèques clientes Cloud Datastore. Pour en savoir plus, consultez les API Ruby Cloud Datastore documentation de référence.

Pour vous authentifier auprès de Cloud Datastore, configurez les identifiants par défaut de l'application. Pour en savoir plus, consultez Configurer l'authentification pour un environnement de développement local.

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

Veuillez noter que, pour la clarté de nos exemples, nous omettons parfois la commande rollback en cas d'échec de la transaction. Dans le code de production, il est important de s'assurer que chaque transaction est validée ou annulée de façon explicite.

Que peut-on faire dans une transaction ?

Les transactions peuvent interroger ou rechercher n'importe quel nombre d'entités. La taille maximale d'une transaction est de 10 Mio. Vous pouvez utiliser une transaction en lecture-écriture ou une transaction en lecture seule.

Isolation et cohérence

Les bases de données en mode Datastore appliquent l'isolation sérialisable. Cela signifie que les données lues ou modifiées par une transaction ne peuvent pas être modifiées simultanément.

Les requêtes et les recherches d'une transaction affichent un instantané cohérent de l'état de la base de données. Cet instantané contient l'effet de toutes les transactions et écritures terminées avant le début de la transaction.

Cet instantané cohérent englobe également les opérations de lecture ayant lieu après les opérations d'écriture dans les transactions. Contrairement à la plupart des bases de données, les requêtes et les recherches au sein d'une transaction en mode Datastore n'affichent pas les résultats des écritures précédentes dans cette transaction. Plus précisément, si une entité est modifiée ou supprimée au sein d'une transaction, une requête ou une recherche renvoie la version d'origine de l'entité au début de la transaction ou ne renvoie rien si l'entité n'existait pas à ce moment-là.

En dehors des transactions, les requêtes et les recherches ont également une isolation sérialisable.

Modes de simultanéité

Firestore en mode Datastore accepte trois modes de simultanéité. Le mode de simultanéité paramètre de base de données qui détermine l'interaction des transactions simultanées. Vous pouvez sélectionnez l'un des modes de simultanéité suivants:

  • Pessimistic

    Les transactions en lecture-écriture utilisent des verrous lecteur-rédacteur pour appliquer l'isolation et la sérialisation. Lorsque deux transactions en lecture-écriture simultanées ou plus lisent ou écrire les mêmes données, le verrou détenu par une transaction peut retarder l'autre les transactions. Si votre transaction ne nécessite aucune écriture, vous pouvez utiliser une transaction en lecture seule pour améliorer les performances et éviter les conflits avec d'autres transactions. Les transactions en lecture seule ne permettent pas ne nécessitent aucun verrouillage.

    Les bases de données Firestore en mode Datastore utilisent le mode de simultanéité pessimiste par défaut.

  • Optimiste

    Lorsque deux transactions en lecture-écriture simultanées ou plus lisent ou écrivent le les mêmes données, seule la première transaction à valider ses modifications réussit. Les autres transactions qui effectuent des écritures échouent lors du commit.

  • Optimiste avec les groupes d'entités

    N'utilisez ce mode de simultanéité que si dépend de la sémantique transactionnelle de groupe d'entités de l'ancienne version de Cloud Datastore. Ce mode de simultanéité impose des limites supplémentaires transactions:

    • Les transactions sont limitées à 25 groupes d'entités.
    • Les écritures dans un groupe d'entités sont limitées à 1 par seconde.
    • Les requêtes dans les transactions doivent être des requêtes ascendantes.

Afficher le mode de simultanéité

Utiliser Firestore projects.databases Ressource REST pour afficher le mode de simultanéité de votre base de données:

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

Modifier le mode de simultanéité

Pour modifier le mode de simultanéité de votre base de données, envoyez une requête PATCH à Firestore projects.databases Ressource 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"

où :

  • CONCURRENCY_MODE est PESSIMISTIC, OPTIMISTIC ou OPTIMISTIC_WITH_ENTITY_GROUPS.
  • PROJECT_ID est l'ID du projet Google Cloud.

Cas d'utilisation des transactions

Une utilisation des transactions consiste à mettre à jour une entité avec une nouvelle valeur de propriété par rapport à sa valeur actuelle. L'exemple transferFunds ci-dessus effectue cette action pour deux entités, en retirant de l'argent d'un compte et en le transférant sur un autre. L'API Datastore n'effectue pas de nouvelles tentatives de transactions. Toutefois, vous pouvez ajouter votre propre logique dans ce domaine, par exemple pour gérer les conflits lorsqu'une autre requête met à jour la même entité au même moment.

C#

Pour savoir comment installer et utiliser la bibliothèque cliente pour Cloud Datastore, consultez Bibliothèques clientes Cloud Datastore. Pour en savoir plus, consultez les API C# Cloud Datastore documentation de référence.

Pour vous authentifier auprès de Cloud Datastore, configurez les identifiants par défaut de l'application. Pour en savoir plus, consultez Configurer l'authentification pour un environnement de développement local.

/// <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

Pour savoir comment installer et utiliser la bibliothèque cliente pour Cloud Datastore, consultez Bibliothèques clientes Cloud Datastore. Pour en savoir plus, consultez les API Go Cloud Datastore documentation de référence.

Pour vous authentifier auprès de Cloud Datastore, configurez les identifiants par défaut de l'application. Pour en savoir plus, consultez Configurer l'authentification pour un environnement de développement local.

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

Pour savoir comment installer et utiliser la bibliothèque cliente pour Cloud Datastore, consultez Bibliothèques clientes Cloud Datastore. Pour en savoir plus, consultez les API Java Cloud Datastore documentation de référence.

Pour vous authentifier auprès de Cloud Datastore, configurez les identifiants par défaut de l'application. Pour en savoir plus, consultez Configurer l'authentification pour un environnement de développement local.

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

Pour savoir comment installer et utiliser la bibliothèque cliente pour Cloud Datastore, consultez Bibliothèques clientes Cloud Datastore. Pour en savoir plus, consultez les API Node.js Cloud Datastore documentation de référence.

Pour vous authentifier auprès de Cloud Datastore, configurez les identifiants par défaut de l'application. Pour en savoir plus, consultez Configurer l'authentification pour un environnement de développement local.

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

Pour savoir comment installer et utiliser la bibliothèque cliente pour Cloud Datastore, consultez Bibliothèques clientes Cloud Datastore. Pour en savoir plus, consultez la documentation de référence de l'API Cloud Datastore PHP.

Pour vous authentifier auprès de Cloud Datastore, configurez les identifiants par défaut de l'application. Pour en savoir plus, consultez Configurer l'authentification pour un environnement de développement local.

$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

Pour savoir comment installer et utiliser la bibliothèque cliente pour Cloud Datastore, consultez la page Bibliothèques clientes Cloud Datastore. Pour en savoir plus, consultez les API Python Cloud Datastore documentation de référence.

Pour vous authentifier auprès de Cloud Datastore, configurez les identifiants par défaut de l'application. Pour en savoir plus, consultez Configurer l'authentification pour un environnement de développement local.

from google.cloud import datastore

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

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

Pour savoir comment installer et utiliser la bibliothèque cliente pour Cloud Datastore, consultez Bibliothèques clientes Cloud Datastore. Pour en savoir plus, consultez les API Ruby Cloud Datastore documentation de référence.

Pour vous authentifier auprès de Cloud Datastore, configurez le service Identifiants par défaut de l'application. Pour en savoir plus, consultez Configurer l'authentification pour un environnement de développement local.

(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

Ici, une transaction est nécessaire, car la valeur balance dans une entité peut être mise à jour par un autre utilisateur après que ce code a récupéré l'objet. Toutefois, cette opération doit s'effectuer avant qu'il n'enregistre l'objet modifié. En l'absence de transaction, la requête de l'utilisateur utilise la valeur balance avant la mise à jour effectuée par l'autre utilisateur, puis la sauvegarde écrase la nouvelle valeur. Avec une transaction, l'application est prévenue de la mise à jour effectuée par l'autre utilisateur.

Une autre utilisation courante des transactions consiste à récupérer une entité avec une clé nommée ou de la créer si elle n'existe pas (cet exemple se base sur l'exemple TaskList illustré dans la section Créer une entité) :

C#

Pour savoir comment installer et utiliser la bibliothèque cliente pour Cloud Datastore, consultez Bibliothèques clientes Cloud Datastore. Pour en savoir plus, consultez les API C# Cloud Datastore documentation de référence.

Pour vous authentifier auprès de Cloud Datastore, configurez les identifiants par défaut de l'application. Pour en savoir plus, consultez Configurer l'authentification pour un environnement de développement local.

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

Go

Pour savoir comment installer et utiliser la bibliothèque cliente pour Cloud Datastore, consultez Bibliothèques clientes Cloud Datastore. Pour en savoir plus, consultez les API Go Cloud Datastore documentation de référence.

Pour vous authentifier auprès de Cloud Datastore, configurez les identifiants par défaut de l'application. Pour en savoir plus, consultez Configurer l'authentification pour un environnement de développement local.

_, 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

Pour savoir comment installer et utiliser la bibliothèque cliente pour Cloud Datastore, consultez Bibliothèques clientes Cloud Datastore. Pour en savoir plus, consultez les API Java Cloud Datastore documentation de référence.

Pour vous authentifier auprès de Cloud Datastore, configurez les identifiants par défaut de l'application. Pour en savoir plus, consultez Configurer l'authentification pour un environnement de développement local.

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

Pour savoir comment installer et utiliser la bibliothèque cliente pour Cloud Datastore, consultez la page Bibliothèques clientes Cloud Datastore. Pour en savoir plus, consultez les API Node.js Cloud Datastore documentation de référence.

Pour vous authentifier auprès de Cloud Datastore, configurez les identifiants par défaut de l'application. Pour en savoir plus, consultez Configurer l'authentification pour un environnement de développement local.

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

Pour savoir comment installer et utiliser la bibliothèque cliente pour Cloud Datastore, consultez Bibliothèques clientes Cloud Datastore. Pour en savoir plus, consultez les API PHP Cloud Datastore documentation de référence.

Pour vous authentifier auprès de Cloud Datastore, configurez les identifiants par défaut de l'application. Pour en savoir plus, consultez Configurer l'authentification pour un environnement de développement local.

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

Python

Pour savoir comment installer et utiliser la bibliothèque cliente pour Cloud Datastore, consultez Bibliothèques clientes Cloud Datastore. Pour en savoir plus, consultez les API Python Cloud Datastore documentation de référence.

Pour vous authentifier auprès de Cloud Datastore, configurez les identifiants par défaut de l'application. Pour en savoir plus, consultez Configurer l'authentification pour un environnement de développement local.

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():
    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

Pour savoir comment installer et utiliser la bibliothèque cliente pour Cloud Datastore, consultez Bibliothèques clientes Cloud Datastore. Pour en savoir plus, consultez les API Ruby Cloud Datastore documentation de référence.

Pour vous authentifier auprès de Cloud Datastore, configurez le service Identifiants par défaut de l'application. Pour en savoir plus, consultez Configurer l'authentification pour un environnement de développement local.

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

Comme précédemment, une transaction est nécessaire dans le cas où un autre utilisateur tente de créer ou de mettre à jour une entité avec le même ID de chaîne. Sans transaction, si l'entité n'existe pas et que deux utilisateurs tentent de la créer, la seconde remplace la première sans savoir ce qu'il s'est passé.

Lorsqu'une transaction échoue, vous pouvez demander à l'application de retenter la transaction jusqu'à ce qu'elle réussisse, ou laisser les utilisateurs traiter l'erreur en la propageant au niveau de l'interface utilisateur de l'application. Il n'est pas nécessaire de créer une boucle afin de retenter chaque transaction.

Transactions en lecture seule

Enfin, vous pouvez utiliser une transaction pour lire un instantané cohérent de la base de données. Cela peut s'avérer utile lorsque plusieurs opérations de lecture sont nécessaires pour afficher une page ou exporter des données qui doivent être cohérentes. Dans ce cas, vous pouvez créer une transaction en lecture seule.

Les transactions en lecture seule ne peuvent pas modifier les entités, mais en contrepartie, elles ne sont en conflit avec aucune autre transaction et n'ont pas besoin d'être relancées. Si vous n'effectuez que des lectures dans une transaction normale en lecture-écriture, cette transaction peut alors entrer en conflit avec une transaction qui modifie les mêmes données.

C#

Pour savoir comment installer et utiliser la bibliothèque cliente pour Cloud Datastore, consultez la page Bibliothèques clientes Cloud Datastore. Pour en savoir plus, consultez les API C# Cloud Datastore documentation de référence.

Pour vous authentifier auprès de Cloud Datastore, configurez les identifiants par défaut de l'application. Pour en savoir plus, consultez Configurer l'authentification pour un environnement de développement local.

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

Pour savoir comment installer et utiliser la bibliothèque cliente pour Cloud Datastore, consultez Bibliothèques clientes Cloud Datastore. Pour en savoir plus, consultez les API Go Cloud Datastore documentation de référence.

Pour vous authentifier auprès de Cloud Datastore, configurez les identifiants par défaut de l'application. Pour en savoir plus, consultez Configurer l'authentification pour un environnement de développement local.

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

Pour savoir comment installer et utiliser la bibliothèque cliente pour Cloud Datastore, consultez Bibliothèques clientes Cloud Datastore. Pour en savoir plus, consultez les API Java Cloud Datastore documentation de référence.

Pour vous authentifier auprès de Cloud Datastore, configurez les identifiants par défaut de l'application. Pour en savoir plus, consultez Configurer l'authentification pour un environnement de développement local.

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

Pour savoir comment installer et utiliser la bibliothèque cliente pour Cloud Datastore, consultez Bibliothèques clientes Cloud Datastore. Pour en savoir plus, consultez les API Node.js Cloud Datastore documentation de référence.

Pour vous authentifier auprès de Cloud Datastore, configurez les identifiants par défaut de l'application. Pour en savoir plus, consultez Configurer l'authentification pour un environnement de développement local.

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

Pour savoir comment installer et utiliser la bibliothèque cliente pour Cloud Datastore, consultez Bibliothèques clientes Cloud Datastore. Pour en savoir plus, consultez la documentation de référence de l'API Cloud Datastore PHP.

Pour vous authentifier auprès de Cloud Datastore, configurez les identifiants par défaut de l'application. Pour en savoir plus, consultez Configurer l'authentification pour un environnement de développement local.

$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

Pour savoir comment installer et utiliser la bibliothèque cliente pour Cloud Datastore, consultez Bibliothèques clientes Cloud Datastore. Pour en savoir plus, consultez les API Python Cloud Datastore documentation de référence.

Pour vous authentifier auprès de Cloud Datastore, configurez les identifiants par défaut de l'application. Pour en savoir plus, consultez Configurer l'authentification pour un environnement de développement local.

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

Pour savoir comment installer et utiliser la bibliothèque cliente pour Cloud Datastore, consultez Bibliothèques clientes Cloud Datastore. Pour en savoir plus, consultez les API Ruby Cloud Datastore documentation de référence.

Pour vous authentifier auprès de Cloud Datastore, configurez les identifiants par défaut de l'application. Pour en savoir plus, consultez Configurer l'authentification pour un environnement de développement local.

# 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

Étape suivante