Transacciones de Cloud Datastore

Una transacción es un conjunto de operaciones de Datastore en una o varias entidades de hasta 25 grupos de entidades. Se garantiza que cada transacción es atómica, lo que significa que las transacciones nunca se aplican parcialmente. Se aplican todas las operaciones de la transacción o no se aplica ninguna.

Usar transacciones

Las transacciones tienen una duración máxima de 270 segundos, con un tiempo de caducidad por inactividad de 10 segundos después de 30 segundos.

Una operación puede fallar en los siguientes casos:

  • Se han intentado realizar demasiadas modificaciones simultáneas en el mismo grupo de entidades.
  • La transacción supera un límite de recursos.
  • Datastore detecta un error interno.

En todos estos casos, la API Datastore devuelve un error.

Las transacciones son una función opcional de Datastore. No es obligatorio usar transacciones para realizar operaciones de Datastore.

Una aplicación puede ejecutar un conjunto de instrucciones y operaciones de Datastore en una sola transacción, de forma que, si alguna instrucción u operación genera una excepción, no se aplique ninguna de las operaciones de Datastore del conjunto. La aplicación define las acciones que se deben realizar en la transacción.

En el siguiente fragmento se muestra cómo realizar una transacción con la API Datastore. Transfiere dinero de una cuenta a otra.

C#

Para saber cómo instalar y usar la biblioteca de cliente de Cloud Datastore, consulta las bibliotecas de cliente de Cloud Datastore. Para obtener más información, consulta la documentación de referencia de la API C# de Cloud Datastore.

Para autenticarte en Cloud Datastore, configura las credenciales predeterminadas de la aplicación. Para obtener más información, consulta el artículo Configurar la autenticación en un entorno de desarrollo 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

Para saber cómo instalar y usar la biblioteca de cliente de Cloud Datastore, consulta las bibliotecas de cliente de Cloud Datastore. Para obtener más información, consulta la documentación de referencia de la API Go de Cloud Datastore.

Para autenticarte en Cloud Datastore, configura las credenciales predeterminadas de la aplicación. Para obtener más información, consulta el artículo Configurar la autenticación en un entorno de desarrollo 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

Para saber cómo instalar y usar la biblioteca de cliente de Cloud Datastore, consulta las bibliotecas de cliente de Cloud Datastore. Para obtener más información, consulta la documentación de referencia de la API Java de Cloud Datastore.

Para autenticarte en Cloud Datastore, configura las credenciales predeterminadas de la aplicación. Para obtener más información, consulta el artículo Configurar la autenticación en un entorno de desarrollo 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

Para saber cómo instalar y usar la biblioteca de cliente de Cloud Datastore, consulta las bibliotecas de cliente de Cloud Datastore. Para obtener más información, consulta la documentación de referencia de la API Node.js de Cloud Datastore.

Para autenticarte en Cloud Datastore, configura las credenciales predeterminadas de la aplicación. Para obtener más información, consulta el artículo Configurar la autenticación en un entorno de desarrollo 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

Para saber cómo instalar y usar la biblioteca de cliente de Cloud Datastore, consulta las bibliotecas de cliente de Cloud Datastore. Para obtener más información, consulta la documentación de referencia de la API PHP de Cloud Datastore.

Para autenticarte en Cloud Datastore, configura las credenciales predeterminadas de la aplicación. Para obtener más información, consulta el artículo Configurar la autenticación en un entorno de desarrollo 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

Para saber cómo instalar y usar la biblioteca de cliente de Cloud Datastore, consulta las bibliotecas de cliente de Cloud Datastore. Para obtener más información, consulta la documentación de referencia de la API Python de Cloud Datastore.

Para autenticarte en Cloud Datastore, configura las credenciales predeterminadas de la aplicación. Para obtener más información, consulta el artículo Configurar la autenticación en un entorno de desarrollo 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

Para saber cómo instalar y usar la biblioteca de cliente de Cloud Datastore, consulta las bibliotecas de cliente de Cloud Datastore. Para obtener más información, consulta la documentación de referencia de la API Ruby de Cloud Datastore.

Para autenticarte en Cloud Datastore, configura las credenciales predeterminadas de la aplicación. Para obtener más información, consulta el artículo Configurar la autenticación en un entorno de desarrollo 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

Ten en cuenta que, para que nuestros ejemplos sean más concisos, a veces omitimos el rollback si la transacción falla. En los códigos de producción es importante asegurarse de que cada transacción se lleve a cabo o se recupere de forma explícita.

Qué se puede hacer en una transacción

Todas las operaciones de Datastore de una transacción pueden operar en un máximo de veinticinco grupos de entidades. Esto incluye realizar consultas de entidades por ancestro, recuperar entidades por clave, así como modificar y eliminar entidades.

Cuando dos o más transacciones intentan modificar simultáneamente entidades en uno o varios grupos de entidades comunes, solo la primera transacción que confirme sus cambios se completará correctamente. El resto fallarán al confirmar los cambios. Debido a este diseño, el uso de grupos de entidades limita el número de escrituras simultáneas que puedes realizar en cualquier entidad de los grupos. Cuando se inicia una transacción, Datastore usa el control de concurrencia optimista comprobando la hora de la última actualización de los grupos de entidades usados en la transacción. Al confirmar una transacción de los grupos de entidades, Datastore vuelve a comprobar la hora de la última actualización de los grupos de entidades utilizados en la transacción. Si ha cambiado desde nuestra comprobación inicial, se devuelve un error. Para obtener una explicación de los grupos de entidades, consulta Rutas de ancestros.

Aislamiento y coherencia

Fuera de las transacciones, el nivel de aislamiento de Datastore es el más parecido a lectura confirmada. Dentro de las transacciones, se aplica el aislamiento serializable. Esto significa que otra transacción no puede modificar simultáneamente los datos que lee o modifica esta transacción. Consulta la wiki sobre el aislamiento serializable y el artículo Aislamiento de transacciones para obtener más información sobre los niveles de aislamiento.

En una transacción, todas las lecturas reflejan el estado actual y coherente de Datastore en el momento en que se inició la transacción. Las consultas y las búsquedas dentro de una transacción tienen garantizada una única instantánea coherente de Datastore desde el inicio de la transacción. Las entidades y las filas de índice de los grupos de entidades de la transacción se actualizan por completo para que las consultas devuelvan el conjunto completo y correcto de entidades de resultado, sin los falsos positivos ni los falsos negativos descritos en Aislamiento de transacciones, que pueden producirse en consultas fuera de las transacciones.

Esta vista de instantánea global también incluye operaciones de lectura producidas después de operaciones de escritura dentro de las transacciones. A diferencia de la mayoría de las bases de datos, las consultas y las operaciones de obtención dentro de una transacción de Datastore no ven los resultados de las escrituras anteriores dentro de esa transacción. En concreto, si se modifica o elimina una entidad en una transacción, una consulta o una búsqueda devuelve la versión original de la entidad al principio de la transacción o nada si la entidad no existía en ese momento.

Usos de las transacciones

Una de las aplicaciones de las transacciones es actualizar una entidad con un nuevo valor de propiedad en relación con su valor actual. En el ejemplo de transferFunds anterior, se hace lo mismo con dos entidades: se retira dinero de una cuenta y se transfiere a otra. La API Datastore no vuelve a intentar las transacciones automáticamente, pero puedes añadir tu propia lógica para volver a intentarlas. Por ejemplo, puedes gestionar los conflictos cuando otra solicitud actualiza la misma entidad al mismo tiempo.

C#

Para saber cómo instalar y usar la biblioteca de cliente de Cloud Datastore, consulta las bibliotecas de cliente de Cloud Datastore. Para obtener más información, consulta la documentación de referencia de la API C# de Cloud Datastore.

Para autenticarte en Cloud Datastore, configura las credenciales predeterminadas de la aplicación. Para obtener más información, consulta el artículo Configurar la autenticación en un entorno de desarrollo 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

Para saber cómo instalar y usar la biblioteca de cliente de Cloud Datastore, consulta las bibliotecas de cliente de Cloud Datastore. Para obtener más información, consulta la documentación de referencia de la API Go de Cloud Datastore.

Para autenticarte en Cloud Datastore, configura las credenciales predeterminadas de la aplicación. Para obtener más información, consulta el artículo Configurar la autenticación en un entorno de desarrollo 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

Para saber cómo instalar y usar la biblioteca de cliente de Cloud Datastore, consulta las bibliotecas de cliente de Cloud Datastore. Para obtener más información, consulta la documentación de referencia de la API Java de Cloud Datastore.

Para autenticarte en Cloud Datastore, configura las credenciales predeterminadas de la aplicación. Para obtener más información, consulta el artículo Configurar la autenticación en un entorno de desarrollo 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

Para saber cómo instalar y usar la biblioteca de cliente de Cloud Datastore, consulta las bibliotecas de cliente de Cloud Datastore. Para obtener más información, consulta la documentación de referencia de la API Node.js de Cloud Datastore.

Para autenticarte en Cloud Datastore, configura las credenciales predeterminadas de la aplicación. Para obtener más información, consulta el artículo Configurar la autenticación en un entorno de desarrollo 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

Para saber cómo instalar y usar la biblioteca de cliente de Cloud Datastore, consulta las bibliotecas de cliente de Cloud Datastore. Para obtener más información, consulta la documentación de referencia de la API PHP de Cloud Datastore.

Para autenticarte en Cloud Datastore, configura las credenciales predeterminadas de la aplicación. Para obtener más información, consulta el artículo Configurar la autenticación en un entorno de desarrollo 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

Para saber cómo instalar y usar la biblioteca de cliente de Cloud Datastore, consulta las bibliotecas de cliente de Cloud Datastore. Para obtener más información, consulta la documentación de referencia de la API Python de Cloud Datastore.

Para autenticarte en Cloud Datastore, configura las credenciales predeterminadas de la aplicación. Para obtener más información, consulta el artículo Configurar la autenticación en un entorno de desarrollo local.

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

Para saber cómo instalar y usar la biblioteca de cliente de Cloud Datastore, consulta las bibliotecas de cliente de Cloud Datastore. Para obtener más información, consulta la documentación de referencia de la API Ruby de Cloud Datastore.

Para autenticarte en Cloud Datastore, configura las credenciales predeterminadas de la aplicación. Para obtener más información, consulta el artículo Configurar la autenticación en un entorno de desarrollo 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

Esto requiere una transacción porque otro usuario puede actualizar el valor de balance en una entidad después de que este código obtenga el objeto, pero antes de que guarde el objeto modificado. Si no hay ninguna transacción, la solicitud del usuario usará el valor de balance anterior a la actualización del otro usuario y la acción de guardar sobrescribirá el nuevo valor. Con una transacción, la aplicación recibe información sobre la actualización del otro usuario.

Otro uso habitual de las transacciones es obtener una entidad con una clave con nombre o crearla si aún no existe (este ejemplo se basa en el ejemplo TaskList de crear una entidad):

C#

Para saber cómo instalar y usar la biblioteca de cliente de Cloud Datastore, consulta las bibliotecas de cliente de Cloud Datastore. Para obtener más información, consulta la documentación de referencia de la API C# de Cloud Datastore.

Para autenticarte en Cloud Datastore, configura las credenciales predeterminadas de la aplicación. Para obtener más información, consulta el artículo Configurar la autenticación en un entorno de desarrollo local.

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

Go

Para saber cómo instalar y usar la biblioteca de cliente de Cloud Datastore, consulta las bibliotecas de cliente de Cloud Datastore. Para obtener más información, consulta la documentación de referencia de la API Go de Cloud Datastore.

Para autenticarte en Cloud Datastore, configura las credenciales predeterminadas de la aplicación. Para obtener más información, consulta el artículo Configurar la autenticación en un entorno de desarrollo 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

Para saber cómo instalar y usar la biblioteca de cliente de Cloud Datastore, consulta las bibliotecas de cliente de Cloud Datastore. Para obtener más información, consulta la documentación de referencia de la API Java de Cloud Datastore.

Para autenticarte en Cloud Datastore, configura las credenciales predeterminadas de la aplicación. Para obtener más información, consulta el artículo Configurar la autenticación en un entorno de desarrollo 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

Para saber cómo instalar y usar la biblioteca de cliente de Cloud Datastore, consulta las bibliotecas de cliente de Cloud Datastore. Para obtener más información, consulta la documentación de referencia de la API Node.js de Cloud Datastore.

Para autenticarte en Cloud Datastore, configura las credenciales predeterminadas de la aplicación. Para obtener más información, consulta el artículo Configurar la autenticación en un entorno de desarrollo 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

Para saber cómo instalar y usar la biblioteca de cliente de Cloud Datastore, consulta las bibliotecas de cliente de Cloud Datastore. Para obtener más información, consulta la documentación de referencia de la API PHP de Cloud Datastore.

Para autenticarte en Cloud Datastore, configura las credenciales predeterminadas de la aplicación. Para obtener más información, consulta el artículo Configurar la autenticación en un entorno de desarrollo local.

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

Python

Para saber cómo instalar y usar la biblioteca de cliente de Cloud Datastore, consulta las bibliotecas de cliente de Cloud Datastore. Para obtener más información, consulta la documentación de referencia de la API Python de Cloud Datastore.

Para autenticarte en Cloud Datastore, configura las credenciales predeterminadas de la aplicación. Para obtener más información, consulta el artículo Configurar la autenticación en un entorno de desarrollo local.

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

Para saber cómo instalar y usar la biblioteca de cliente de Cloud Datastore, consulta las bibliotecas de cliente de Cloud Datastore. Para obtener más información, consulta la documentación de referencia de la API Ruby de Cloud Datastore.

Para autenticarte en Cloud Datastore, configura las credenciales predeterminadas de la aplicación. Para obtener más información, consulta el artículo Configurar la autenticación en un entorno de desarrollo 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

Al igual que antes, las transacciones son necesarias en caso de que un usuario intente crear o modificar una entidad con el mismo ID de cadena que otro. Sin una transacción, si la entidad no existe y dos usuarios intentan crearla, la operación del segundo sobrescribe la del primero sin saberlo.

Cuando falla una transacción, puedes hacer que tu aplicación vuelva a intentarla hasta que se complete correctamente o dejar que tus usuarios gestionen el error propagándolo al nivel de la interfaz de usuario de tu aplicación. No es necesario crear un loop de nuevo intento para cada transacción.

Por último, puedes usar una transacción para leer una captura coherente de Datastore. Esto puede resultar útil cuando se necesitan varias operaciones de lectura para mostrar una página o exportar datos que deban ser coherentes. Este tipo de transacciones se suelen denominar transacciones de solo lectura, ya que no realizan ninguna escritura. Las transacciones de solo lectura de un solo grupo nunca fallan debido a modificaciones simultáneas, por lo que no tienes que implementar reintentos en caso de fallo. Sin embargo, las transacciones de grupos de varias entidades pueden fallar debido a modificaciones simultáneas, por lo que deberían tener reintentos.

C#

Para saber cómo instalar y usar la biblioteca de cliente de Cloud Datastore, consulta las bibliotecas de cliente de Cloud Datastore. Para obtener más información, consulta la documentación de referencia de la API C# de Cloud Datastore.

Para autenticarte en Cloud Datastore, configura las credenciales predeterminadas de la aplicación. Para obtener más información, consulta el artículo Configurar la autenticación en un entorno de desarrollo 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

Para saber cómo instalar y usar la biblioteca de cliente de Cloud Datastore, consulta las bibliotecas de cliente de Cloud Datastore. Para obtener más información, consulta la documentación de referencia de la API Go de Cloud Datastore.

Para autenticarte en Cloud Datastore, configura las credenciales predeterminadas de la aplicación. Para obtener más información, consulta el artículo Configurar la autenticación en un entorno de desarrollo 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

Para saber cómo instalar y usar la biblioteca de cliente de Cloud Datastore, consulta las bibliotecas de cliente de Cloud Datastore. Para obtener más información, consulta la documentación de referencia de la API Java de Cloud Datastore.

Para autenticarte en Cloud Datastore, configura las credenciales predeterminadas de la aplicación. Para obtener más información, consulta el artículo Configurar la autenticación en un entorno de desarrollo 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

Para saber cómo instalar y usar la biblioteca de cliente de Cloud Datastore, consulta las bibliotecas de cliente de Cloud Datastore. Para obtener más información, consulta la documentación de referencia de la API Node.js de Cloud Datastore.

Para autenticarte en Cloud Datastore, configura las credenciales predeterminadas de la aplicación. Para obtener más información, consulta el artículo Configurar la autenticación en un entorno de desarrollo 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

Para saber cómo instalar y usar la biblioteca de cliente de Cloud Datastore, consulta las bibliotecas de cliente de Cloud Datastore. Para obtener más información, consulta la documentación de referencia de la API PHP de Cloud Datastore.

Para autenticarte en Cloud Datastore, configura las credenciales predeterminadas de la aplicación. Para obtener más información, consulta el artículo Configurar la autenticación en un entorno de desarrollo 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

Para saber cómo instalar y usar la biblioteca de cliente de Cloud Datastore, consulta las bibliotecas de cliente de Cloud Datastore. Para obtener más información, consulta la documentación de referencia de la API Python de Cloud Datastore.

Para autenticarte en Cloud Datastore, configura las credenciales predeterminadas de la aplicación. Para obtener más información, consulta el artículo Configurar la autenticación en un entorno de desarrollo 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

Para saber cómo instalar y usar la biblioteca de cliente de Cloud Datastore, consulta las bibliotecas de cliente de Cloud Datastore. Para obtener más información, consulta la documentación de referencia de la API Ruby de Cloud Datastore.

Para autenticarte en Cloud Datastore, configura las credenciales predeterminadas de la aplicación. Para obtener más información, consulta el artículo Configurar la autenticación en un entorno de desarrollo 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

Transacciones y grupos de entidades

Un grupo de entidades es un conjunto de entidades conectadas a través de la ascendencia a un elemento raíz común. La organización de los datos en grupos de entidades puede limitar las transacciones que se pueden realizar:

  • Todos los datos a los que accede una transacción deben estar incluidos en un máximo de 25 grupos de entidades.
  • Si quieres usar consultas en una transacción, tus datos deben organizarse en grupos de entidades de forma que puedas especificar filtros de ancestros que coincidan con los datos correctos.
  • Hay un límite de rendimiento de escritura de aproximadamente una transacción por segundo en un solo grupo de entidades. Esta limitación se debe a que Datastore realiza una replicación síncrona sin maestro de cada grupo de entidades en una zona geográfica amplia para ofrecer una alta fiabilidad y tolerancia a fallos.

En muchas aplicaciones, es aceptable usar la coherencia final (es decir, una consulta que no sea de ancestro y que abarque varios grupos de entidades, que a veces puede devolver datos ligeramente obsoletos) para obtener una visión general de datos no relacionados y, a continuación, usar la coherencia fuerte (una consulta de ancestro o un lookup de una sola entidad) para ver o editar un solo conjunto de datos muy relacionados. En estas aplicaciones, suele ser una buena estrategia usar un grupo de entidades independiente para cada conjunto de datos muy relacionados. Para obtener más información, consulta Coherencia de los datos.

Siguientes pasos