Transações do Cloud Datastore

Uma transação é um conjunto de operações do Datastore em uma ou mais entidades em até 25 grupos de entidades. Todas as transações são atômicas, o que significa que elas nunca são aplicadas parcialmente. Ou todas as operações na transação são aplicadas ou nenhuma delas é aplicada.

Como usar transações

As transações têm uma duração máxima de 270 segundos, com um tempo de expiração por inatividade de 10 segundos após 30 segundos.

Uma operação poderá falhar quando:

  • muitas modificações simultâneas forem tentadas no mesmo grupo de entidades;
  • a transação exceder um limite de recursos;
  • o Datastore encontrar um erro interno.

Em todos esses casos, a API do Datastore retornará um erro.

As transações são um recurso opcional do Datastore. Elas não precisam ser usadas para realizar operações do Datastore.

Um aplicativo pode executar um conjunto de declarações e operações no Datastore em uma única transação, de tal maneira que se qualquer declaração ou operação emitir uma exceção, nenhuma das operações do Datastore presentes no conjunto será aplicada. O aplicativo define as ações a serem executadas na transação.

O snippet a seguir mostra como realizar uma transação usando a API do Datastore. A transação é uma transferência monetária de uma conta para outra.

C#

Para saber como instalar e usar a biblioteca de cliente para o Cloud Datastore, consulte Bibliotecas de cliente do Cloud Datastore. Para mais informações, consulte a documentação de referência da API Cloud Datastore C#.

Para autenticar no Cloud Datastore, configure o Application Default Credentials. Para mais informações, consulte Configurar a autenticação para um ambiente de desenvolvimento 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 como instalar e usar a biblioteca de cliente para o Cloud Datastore, consulte Bibliotecas de cliente do Cloud Datastore. Para mais informações, consulte a documentação de referência da API Cloud Datastore Go.

Para autenticar no Cloud Datastore, configure o Application Default Credentials. Para mais informações, consulte Configurar a autenticação para um ambiente de desenvolvimento 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 como instalar e usar a biblioteca de cliente para o Cloud Datastore, consulte Bibliotecas de cliente do Cloud Datastore. Para mais informações, consulte a documentação de referência da API Cloud Datastore Java.

Para autenticar no Cloud Datastore, configure o Application Default Credentials. Para mais informações, consulte Configurar a autenticação para um ambiente de desenvolvimento 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 como instalar e usar a biblioteca de cliente para o Cloud Datastore, consulte Bibliotecas de cliente do Cloud Datastore. Para mais informações, consulte a documentação de referência da API Cloud Datastore Node.js.

Para autenticar no Cloud Datastore, configure o Application Default Credentials. Para mais informações, consulte Configurar a autenticação para um ambiente de desenvolvimento 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 como instalar e usar a biblioteca de cliente para o Cloud Datastore, consulte Bibliotecas de cliente do Cloud Datastore. Para mais informações, consulte a documentação de referência da API Cloud Datastore PHP.

Para autenticar no Cloud Datastore, configure o Application Default Credentials. Para mais informações, consulte Configurar a autenticação para um ambiente de desenvolvimento local.

/**
 * Update two entities in a transaction.
 *
 * @param DatastoreClient $datastore
 * @param Key $fromKey
 * @param Key $toKey
 * @param $amount
 */
function transfer_funds(
    DatastoreClient $datastore,
    Key $fromKey,
    Key $toKey,
    $amount
) {
    $transaction = $datastore->transaction();
    // 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 como instalar e usar a biblioteca de cliente para o Cloud Datastore, consulte Bibliotecas de cliente do Cloud Datastore. Para mais informações, consulte a documentação de referência da API Cloud Datastore Python.

Para autenticar no Cloud Datastore, configure o Application Default Credentials. Para mais informações, consulte Configurar a autenticação para um ambiente de desenvolvimento 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 como instalar e usar a biblioteca de cliente para o Cloud Datastore, consulte Bibliotecas de cliente do Cloud Datastore. Para mais informações, consulte a documentação de referência da API Cloud Datastore Ruby.

Para autenticar no Cloud Datastore, configure o Application Default Credentials. Para mais informações, consulte Configurar a autenticação para um ambiente de desenvolvimento 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

Para manter nossos exemplos mais sucintos, às vezes omitimos rollback se a transação falha. Em código de produção, é importante garantir que cada transação seja executada explicitamente ou revertida.

O que pode ser feito em uma transação

Todas as operações do Datastore em uma transação podem operar em, no máximo, vinte e cinco grupos de entidades. Isso inclui fazer consultas por entidades pelo ancestral, recuperar entidades pela chave, atualizar as entidades e excluir as entidades.

Quando duas ou mais transações tentam, simultaneamente, modificar entidades em um ou mais grupos de entidades comuns, somente a primeira transação a executar commit das suas alterações pode ser bem-sucedida. Todas as outras falharão no commit. Devido a esse design, o uso de grupos de entidades limita o número de gravações simultâneas que é possível fazer em qualquer entidade nos grupos. Quando uma transação é iniciada, o Datastore usa o controle de simultaneidade otimista verificando o horário da última atualização dos grupos de entidades usados na transação. Após a confirmação de uma transação nos grupos de entidades, o Datastore verifica novamente o horário da última atualização dos grupos de entidades usados na transação. Se ela tiver sido alterada desde a verificação inicial, um erro será retornado. Para mais detalhes sobre grupos de entidades, consulte Caminhos de ancestral.

Isolamento e consistência

Fora das transações, o nível de isolamento do Datastore está mais próximo da confirmação de leitura. Dentro, por sua vez, o isolamento serializável é imposto. Isso significa que outra transação não pode modificar simultaneamente os dados lidos ou modificados por essa transação. Para mais informações sobre níveis de isolamento, leia a wiki sobre isolamento serializável e o artigo sobre isolamento da transação.

Em uma transação, todas as leituras refletem o estado atual e consistente do Datastore no momento em que a transação foi iniciada. As consultas e as pesquisas dentro de uma transação garantem a visualização de um snapshot único e consistente do Datastore desde o início da transação. Nos grupos de entidades da transação, as linhas de índice e entidades são totalmente atualizadas para que as consultas retornem o conjunto completo e correto de resultados da entidade. Isso evita os falsos positivos ou falsos negativos, descritos em Isolamento da transação, que podem ocorrer em consultas fora das transações.

A visualização desse instantâneo consistente também se estende a leituras após gravações dentro de transações. Diferentemente da maioria dos bancos de dados, as consultas e os gets dentro de uma transação do Datastore não exibem os resultados de gravações anteriores dentro dessa transação. Especificamente, se uma entidade for alterada ou excluída em uma transação, uma consulta ou pesquisa retornará a versão original da entidade no início da transação ou nada, se a entidade não existia.

Usos das transações

Um dos usos das transações é a atualização de uma entidade com um novo valor de propriedade relativo ao seu valor atual. O exemplo transferFunds acima faz isso para duas entidades, retirando dinheiro de uma conta e transferindo-o para outra. A API Datastore não tenta repetir transações automaticamente, mas é possível adicionar sua própria lógica para repeti-las, por exemplo, para resolver conflitos quando outra solicitação atualiza a mesma entidade ao mesmo tempo.

C#

Para saber como instalar e usar a biblioteca de cliente para o Cloud Datastore, consulte Bibliotecas de cliente do Cloud Datastore. Para mais informações, consulte a documentação de referência da API Cloud Datastore C#.

Para autenticar no Cloud Datastore, configure o Application Default Credentials. Para mais informações, consulte Configurar a autenticação para um ambiente de desenvolvimento 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 como instalar e usar a biblioteca de cliente para o Cloud Datastore, consulte Bibliotecas de cliente do Cloud Datastore. Para mais informações, consulte a documentação de referência da API Cloud Datastore Go.

Para autenticar no Cloud Datastore, configure o Application Default Credentials. Para mais informações, consulte Configurar a autenticação para um ambiente de desenvolvimento 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 como instalar e usar a biblioteca de cliente para o Cloud Datastore, consulte Bibliotecas de cliente do Cloud Datastore. Para mais informações, consulte a documentação de referência da API Cloud Datastore Java.

Para autenticar no Cloud Datastore, configure o Application Default Credentials. Para mais informações, consulte Configurar a autenticação para um ambiente de desenvolvimento 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 como instalar e usar a biblioteca de cliente para o Cloud Datastore, consulte Bibliotecas de cliente do Cloud Datastore. Para mais informações, consulte a documentação de referência da API Cloud Datastore Node.js.

Para autenticar no Cloud Datastore, configure o Application Default Credentials. Para mais informações, consulte Configurar a autenticação para um ambiente de desenvolvimento 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 como instalar e usar a biblioteca de cliente para o Cloud Datastore, consulte Bibliotecas de cliente do Cloud Datastore. Para mais informações, consulte a documentação de referência da API Cloud Datastore PHP.

Para autenticar no Cloud Datastore, configure o Application Default Credentials. Para mais informações, consulte Configurar a autenticação para um ambiente de desenvolvimento local.

$retries = 5;
for ($i = 0; $i < $retries; $i++) {
    try {
        transfer_funds($datastore, $fromKey, $toKey, 10);
    } catch (\Google\Cloud\Core\Exception\ConflictException $e) {
        // if $i >= $retries, the failure is final
        continue;
    }
    // Succeeded!
    break;
}

Python

Para saber como instalar e usar a biblioteca de cliente para o Cloud Datastore, consulte Bibliotecas de cliente do Cloud Datastore. Para mais informações, consulte a documentação de referência da API Cloud Datastore Python.

Para autenticar no Cloud Datastore, configure o Application Default Credentials. Para mais informações, consulte Configurar a autenticação para um ambiente de desenvolvimento 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

Para saber como instalar e usar a biblioteca de cliente para o Cloud Datastore, consulte Bibliotecas de cliente do Cloud Datastore. Para mais informações, consulte a documentação de referência da API Cloud Datastore Ruby.

Para autenticar no Cloud Datastore, configure o Application Default Credentials. Para mais informações, consulte Configurar a autenticação para um ambiente de desenvolvimento 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

Isso requer uma transação porque o valor de balance em uma entidade pode ser atualizado por outro usuário após esse código buscar o objeto, mas antes de salvar o objeto modificado. Sem uma transação, a solicitação do usuário usa o valor de balance antes da atualização do outro usuário, e a gravação substitui o novo valor. Com uma transação, o aplicativo é informado sobre a atualização.

Outro uso comum das transações é buscar uma entidade com uma chave nomeada, ou criá-la, caso ela ainda não exista (este exemplo é baseado no exemplo da TaskList de como criar uma entidade):

C#

Para saber como instalar e usar a biblioteca de cliente para o Cloud Datastore, consulte Bibliotecas de cliente do Cloud Datastore. Para mais informações, consulte a documentação de referência da API Cloud Datastore C#.

Para autenticar no Cloud Datastore, configure o Application Default Credentials. Para mais informações, consulte Configurar a autenticação para um ambiente de desenvolvimento local.

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

Go

Para saber como instalar e usar a biblioteca de cliente para o Cloud Datastore, consulte Bibliotecas de cliente do Cloud Datastore. Para mais informações, consulte a documentação de referência da API Cloud Datastore Go.

Para autenticar no Cloud Datastore, configure o Application Default Credentials. Para mais informações, consulte Configurar a autenticação para um ambiente de desenvolvimento 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 como instalar e usar a biblioteca de cliente para o Cloud Datastore, consulte Bibliotecas de cliente do Cloud Datastore. Para mais informações, consulte a documentação de referência da API Cloud Datastore Java.

Para autenticar no Cloud Datastore, configure o Application Default Credentials. Para mais informações, consulte Configurar a autenticação para um ambiente de desenvolvimento 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 como instalar e usar a biblioteca de cliente para o Cloud Datastore, consulte Bibliotecas de cliente do Cloud Datastore. Para mais informações, consulte a documentação de referência da API Cloud Datastore Node.js.

Para autenticar no Cloud Datastore, configure o Application Default Credentials. Para mais informações, consulte Configurar a autenticação para um ambiente de desenvolvimento 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 como instalar e usar a biblioteca de cliente para o Cloud Datastore, consulte Bibliotecas de cliente do Cloud Datastore. Para mais informações, consulte a documentação de referência da API Cloud Datastore PHP.

Para autenticar no Cloud Datastore, configure o Application Default Credentials. Para mais informações, consulte Configurar a autenticação para um ambiente de desenvolvimento local.

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

Python

Para saber como instalar e usar a biblioteca de cliente para o Cloud Datastore, consulte Bibliotecas de cliente do Cloud Datastore. Para mais informações, consulte a documentação de referência da API Cloud Datastore Python.

Para autenticar no Cloud Datastore, configure o Application Default Credentials. Para mais informações, consulte Configurar a autenticação para um ambiente de desenvolvimento 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

Para saber como instalar e usar a biblioteca de cliente para o Cloud Datastore, consulte Bibliotecas de cliente do Cloud Datastore. Para mais informações, consulte a documentação de referência da API Cloud Datastore Ruby.

Para autenticar no Cloud Datastore, configure o Application Default Credentials. Para mais informações, consulte Configurar a autenticação para um ambiente de desenvolvimento 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

Como antes, uma transação é necessária para manipular o caso quando outro usuário estiver tentando criar ou atualizar uma entidade com o mesmo ID de string. Sem uma transação, se a entidade não existir e dois usuários tentarem criá-la, o segundo substituirá o primeiro sem saber o que aconteceu.

Quando uma transação falha, é possível fazer com que o app repita a transação até ter êxito, ou é possível deixar que os usuários lidem com o erro propagando-o até o nível de interface do usuário do app. Não é necessário criar um ciclo de repetições em torno de cada transação.

Por fim, você pode usar uma transação para ler um snapshot consistente do Datastore. Isso pode ser útil quando várias leituras forem necessárias para renderizar uma página ou para exportar dados que precisem ser consistentes. Esses tipos de transações são frequentemente chamados de transações somente leitura, uma vez que não realizam gravações. As transações somente leitura de um único grupo nunca falham devido a modificações simultâneas, portanto, você não precisa implementar repetições após falha. No entanto, transações de vários grupos de entidades podem falhar devido a modificações simultâneas, havendo necessidade de repetições.

C#

Para saber como instalar e usar a biblioteca de cliente para o Cloud Datastore, consulte Bibliotecas de cliente do Cloud Datastore. Para mais informações, consulte a documentação de referência da API Cloud Datastore C#.

Para autenticar no Cloud Datastore, configure o Application Default Credentials. Para mais informações, consulte Configurar a autenticação para um ambiente de desenvolvimento 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 como instalar e usar a biblioteca de cliente para o Cloud Datastore, consulte Bibliotecas de cliente do Cloud Datastore. Para mais informações, consulte a documentação de referência da API Cloud Datastore Go.

Para autenticar no Cloud Datastore, configure o Application Default Credentials. Para mais informações, consulte Configurar a autenticação para um ambiente de desenvolvimento 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 como instalar e usar a biblioteca de cliente para o Cloud Datastore, consulte Bibliotecas de cliente do Cloud Datastore. Para mais informações, consulte a documentação de referência da API Cloud Datastore Java.

Para autenticar no Cloud Datastore, configure o Application Default Credentials. Para mais informações, consulte Configurar a autenticação para um ambiente de desenvolvimento 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 como instalar e usar a biblioteca de cliente para o Cloud Datastore, consulte Bibliotecas de cliente do Cloud Datastore. Para mais informações, consulte a documentação de referência da API Cloud Datastore Node.js.

Para autenticar no Cloud Datastore, configure o Application Default Credentials. Para mais informações, consulte Configurar a autenticação para um ambiente de desenvolvimento 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 como instalar e usar a biblioteca de cliente para o Cloud Datastore, consulte Bibliotecas de cliente do Cloud Datastore. Para mais informações, consulte a documentação de referência da API Cloud Datastore PHP.

Para autenticar no Cloud Datastore, configure o Application Default Credentials. Para mais informações, consulte Configurar a autenticação para um ambiente de desenvolvimento 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 como instalar e usar a biblioteca de cliente para o Cloud Datastore, consulte Bibliotecas de cliente do Cloud Datastore. Para mais informações, consulte a documentação de referência da API Cloud Datastore Python.

Para autenticar no Cloud Datastore, configure o Application Default Credentials. Para mais informações, consulte Configurar a autenticação para um ambiente de desenvolvimento 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 como instalar e usar a biblioteca de cliente para o Cloud Datastore, consulte Bibliotecas de cliente do Cloud Datastore. Para mais informações, consulte a documentação de referência da API Cloud Datastore Ruby.

Para autenticar no Cloud Datastore, configure o Application Default Credentials. Para mais informações, consulte Configurar a autenticação para um ambiente de desenvolvimento 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

Transações e grupos de entidades

Um grupo de entidades é um conjunto de entidades conectadas através de ancestral a um elemento raiz comum. A organização dos dados em grupos de entidades pode limitar quais transações podem ser realizadas:

  • Todos os dados acessados por uma transação devem estar contidos em, no máximo, 25 grupos de entidades.
  • Se você quiser usar consultas em uma transação, os dados precisam estar organizados em grupos de entidades para que você possa especificar filtros de ancestral que corresponderão aos dados corretos.
  • Há um limite de capacidade de gravação de aproximadamente uma transação por segundo em um único grupo de entidades. Essa limitação existe porque, para fornecer alta confiabilidade e tolerância a falhas, o Datastore executa a replicação síncrona sem mestre de cada grupo de entidades em uma ampla área geográfica.

Em muitos aplicativos, é aceitável usar a consistência eventual (ou seja, uma consulta que não seja de ancestral abrangendo vários grupos de entidades, que às vezes pode retornar dados um pouco desatualizados) para uma visualização ampla de dados não relacionados e depois usar a consistência forte (uma consulta de ancestral ou uma operação lookup para uma única entidade) para visualizar ou editar um único conjunto de dados altamente relacionados. Em tais aplicativos, geralmente é uma boa abordagem usar um grupo de entidades separado para cada conjunto de dados altamente relacionados. Para saber mais, veja Consistência de dados.

A seguir