API App Engine Datastore para Java 8

Neste documento, você verá a descrição do modelo de dados para objetos armazenados no Cloud Datastore, de como as consultas são estruturadas usando a API e de como as transações são processadas.

Entidades

Os objetos do Cloud Datastore são conhecidos como entidades. Uma entidade tem uma ou mais propriedades nomeadas, que podem ter um ou mais valores. Os valores da propriedade pertencem a uma série de tipos de dados, como números inteiros, números de ponto flutuante, strings, datas e dados binários, entre outros. Uma consulta em uma propriedade com múltiplos valores testa se qualquer um dos valores satisfaz os critérios de consulta. Isso torna essas propriedades úteis em testes de associação.

Tipos, chaves e identificadores

Cada entidade do Cloud Datastore é de um determinado tipo que a classifica para fins de consultas. Por exemplo, um aplicativo de recursos humanos representa cada funcionário de uma empresa com uma entidade do tipo Employee. Além disso, cada entidade tem a própria chave para garantir a identificação de maneira exclusiva. A chave consiste nos seguintes componentes:

  • Um tipo de entidade.
  • Um identificador, sendo ele um dos seguintes:
    • uma string de nome da chave;
    • um código de número inteiro.
  • Um caminho ancestral opcional que localiza a entidade na hierarquia do Cloud Datastore.

O identificador é atribuído quando a entidade é criada. Por ser parte da chave da entidade, ele é associado permanentemente à entidade e não pode ser alterado. Pode ser atribuído de duas formas:

  • O aplicativo especifica a própria string de nome da chave para a entidade.
  • O Cloud Datastore atribui automaticamente à entidade um código numérico inteiro.

Caminhos ancestrais

As entidades do Cloud Datastore formam um espaço hierarquicamente estruturado, semelhante à estrutura de diretórios de um sistema de arquivos. Ao criar uma entidade, é possível designar outra entidade como pai e a nova é a entidade filho (observe que, diferentemente do que ocorre em um sistema de arquivos, a entidade pai não precisa existir de verdade). Uma entidade sem mãe é uma entidade raiz. A associação entre uma entidade e a entidade pai é permanente e não pode ser alterada depois que a entidade é criada. O Cloud Datastore nunca atribuirá o mesmo código numérico a duas entidades com o mesmo pai ou a duas entidades raiz (sem pai).

O pai de uma entidade, o pai do pai, e assim por diante são ancestrais dela. O filho, o filho do filho, e assim por diante são descendentes dela. Uma entidade raiz e todos os descendentes pertencem ao mesmo grupo de entidades. A sequência de entidades começando com uma entidade raiz e prosseguindo de pai para filho, levando a uma determinada entidade, constitui o caminho do ancestral dessa entidade. A chave completa que identifica a entidade consiste em uma sequência de pares de identificadores de tipo que especifica seu caminho ancestral e termina com os da própria entidade:

[Person:GreatGrandpa, Person:Grandpa, Person:Dad, Person:Me]

Para uma entidade raiz, o caminho ancestral está vazio, e a chave consiste unicamente no próprio tipo e identificador da entidade:

[Person:GreatGrandpa]

Esse conceito é ilustrado pelo seguinte diagrama:

Mostra a relação entre a entidade raiz e as entidades filho no grupo de entidades

Consultas e índices

Além de recuperar entidades do Cloud Datastore diretamente por meio das chaves delas, um aplicativo pode realizar uma consulta para recuperar as entidades pelos valores das propriedades delas. A consulta opera em entidades de um determinado tipo. Ela pode especificar filtros nos valores de propriedades, chaves e ancestrais das entidades e pode retornar zero ou mais entidades como resultados. Também especifica ordens de classificação para colocar os resultados em sequência pelos respectivos valores de propriedade. Os resultados incluem todas as entidades que tenham pelo menos um valor (que pode ser nulo) para cada propriedade nomeada nos filtros e ordens de classificação e que também tenham valores de propriedade que atendam a todos os critérios de filtro especificados. A consulta pode retornar entidades de projeção, inteiras ou apenas chaves de entidade.

Uma consulta típica inclui:

Quando executada, a consulta recupera todas as entidades do tipo determinado que satisfaçam a todos os filtros fornecidos, classificadas na ordem especificada. As consultas são executadas no modo de somente leitura.

Observação: para economizar memória e melhorar o desempenho, sempre que possível uma consulta deve especificar um limite para o número de resultados retornados.

Uma consulta também pode incluir um filtro de ancestral, que limita os resultados apenas ao grupo de entidades descendentes de um ancestral especificado. Essa consulta é conhecida como consulta de ancestral. Por padrão, ela retorna resultados com consistência forte (em inglês), com garantia de atualização de acordo com as alterações mais recentes dos dados. Por outro lado, as consultas que não são de ancestral podem abranger todo o Cloud Datastore, em vez de um único grupo de entidades, mas têm apenas consistência eventual e talvez retornem resultados desatualizados. Caso a consistência forte seja importante para o aplicativo, leve isso em conta ao estruturar os dados. Coloque entidades relacionadas no mesmo grupo, assim elas serão recuperadas com uma consulta de ancestral em vez de não ancestral. Consulte Como estruturar dados para consistência forte para receber mais informações.

O App Engine predefine um índice simples em cada propriedade de uma entidade. Um aplicativo do App Engine pode definir outros índices personalizados em um arquivo de configuração de índice chamado datastore-indexes.xml, que é gerado no diretório /war/WEB-INF/appengine-generated do seu aplicativo. O servidor de desenvolvimento adiciona sugestões a esse arquivo automaticamente quando encontra consultas não executáveis com os índices atuais. É possível ajustar os índices manualmente editando o arquivo antes de fazer upload do aplicativo.

Veja uma discussão mais detalhada sobre índices e consultas em Seleção de índice e pesquisa avançada.

Observação: o mecanismo de consulta baseado em índice é compatível com uma grande variedade de consultas e adequado à maioria dos aplicativos. No entanto, ele não aceita alguns tipos de consulta comuns em outras tecnologias de banco de dados. Em especial, as consultas agregadas e conjuntas não são compatíveis com o mecanismo de consulta do Cloud Datastore. Para conhecer as limitações das consultas do Cloud Datastore, consulte a página Consultas do Datastore.

Transações

Toda tentativa de inserir, atualizar ou excluir uma entidade ocorre no contexto de uma transação. Uma única transação pode incluir qualquer número dessas operações. Para manter a consistência dos dados, a transação garante a aplicação de todas as operações nela contidas no Cloud Datastore como uma unidade ou, em caso de falha de alguma operação, que nenhuma delas seja aplicada.

É possível executar diversas ações em uma entidade dentro de uma única transação. Por exemplo, para incrementar um campo de contador em um objeto, é preciso ler o valor do contador, calcular o novo valor e armazená-lo novamente. Sem uma transação, é possível que outro processo incremente o contador entre o horário em que o valor é lido e o horário em que é atualizado, causando a substituição, pelo aplicativo, do valor atualizado. Fazer leitura, cálculo e gravação em uma única transação garante que nenhum outro processo interfira no incremento.

Transações e grupos de entidades

Somente consultas de ancestrais são permitidas dentro de uma transação, ou seja, cada consulta transacional é limitada a um único grupo de entidades. A própria transação é aplicada a várias entidades pertencentes a um único grupo ou, no caso de uma transação entre grupos, a até 25 grupos diferentes de entidades.

O Cloud Datastore usa simultaneidade otimista para gerenciar transações. Quando duas ou mais transações tentam alterar o mesmo grupo de entidades ao mesmo tempo, seja atualizando entidades existentes ou criando novas, a primeira transação a ser confirmada será bem-sucedida e as demais falharão. Em seguida, essas outras transações poderão ser repetidas nos dados atualizados. Observe que isso limita o número de gravações simultâneas a serem feitas em qualquer entidade em um determinado grupo.

Transações entre grupos

Uma transação em entidades que pertençam a diferentes grupos é chamada de transação entre grupos (XG, na sigla em inglês). A transação pode ser aplicada no máximo em vinte e cinco grupos de entidades e será bem-sucedida desde que nenhuma transação simultânea interfira em qualquer um dos grupos de entidades aos quais ela se aplica. Isso torna a organização de dados mais flexível, porque você não tem obrigação de colocar dados diferentes no mesmo ancestral apenas para executar gravações atômicas neles.

Assim como em uma transação de um único grupo, não é possível executar uma consulta não ancestral em uma transação XG. No entanto, é possível realizar consultas ancestrais em grupos de entidades distintos. As consultas não transacionais (não ancestrais) conseguem ver todos, alguns ou nenhum resultado de uma transação confirmada anteriormente. Para mais informações a respeito dessa questão, consulte Gravações do Cloud Datastore e Visibilidade de dados. No entanto, as chances de essas consultas não transacionais retornarem os resultados de uma transação parcialmente confirmada de XG são maiores do que as de uma transação parcialmente confirmada de um único grupo.

Uma transação XG que interfira em um único grupo de entidades tem exatamente o mesmo desempenho e custo de uma transação não XG de um único grupo. Em uma transação XG que interfira em diversos grupos de entidades, as operações têm o mesmo custo de uma transação não XG, mas podem sofrer maior latência.

Gravações e visibilidade de dados do Cloud Datastore

Os dados são gravados no Cloud Datastore em duas fases:

  1. Na fase de Commit, o registro dos dados da entidade é feito nos registros de transação da maioria das réplicas. As réplicas em que o registro não foi feito são marcadas como não tendo registros atualizados.
  2. Na fase de Apply, que ocorre de maneira independente em cada réplica, duas ações são realizadas em paralelo:
    • Os dados da entidade são gravados nessa réplica.
    • As linhas de índice para a entidade são gravadas nessa réplica. Observe que isso pode levar mais tempo do que para gravar os dados propriamente ditos.

A operação de gravação retorna imediatamente após a fase de Commit e a fase de Apply ocorre de maneira assíncrona, possivelmente tanto em momentos diferentes em cada réplica quanto com atrasos de algumas centenas de milissegundos ou mais, após a conclusão da fase de Commit. Quando ocorre uma falha durante a fase de Commit, são feitas tentativas automáticas. No entanto, caso o problema persista, o Cloud Datastore retornará uma mensagem de erro que é recebida pelo aplicativo como uma exceção. Quando há êxito na fase de Commit e falha na fase de Apply em uma determinada réplica, a Apply é enviada para conclusão dessa réplica em uma das situações abaixo:

  • Varredura periódica do Cloud Datastore, verificando jobs não concluídos de Commit e aplicando-os.
  • Determinadas operações, como get, put, delete e consultas de ancestrais, que usam o grupo de entidades afetadas, fazem com que as alterações do commit que ainda não tiverem sido aplicadas sejam concluídas na réplica em que estão sendo executadas antes de prosseguir com a nova operação.

Este comportamento de gravação tem várias implicações sobre como e quando os dados estarão visíveis para o aplicativo em diferentes partes das fases de Commit e Apply:

  • Caso uma operação de gravação relate um erro de tempo limite, não será possível determinar o sucesso ou a falha da operação sem tentar ler os dados.
  • Como a função get e as consultas de ancestrais do Cloud Datastore aplicam modificações pendentes à réplica em que estão sendo executadas, essas operações sempre têm uma visão consistente de todas as transações anteriores bem-sucedidas. Isso significa que uma operação get que procura uma entidade atualizada pela chave correspondente tem a garantia de ver a versão mais recente dessa entidade.
  • As consultas não ancestrais retornam resultados desatualizados porque podem estar em execução em uma réplica em que as transações mais recentes ainda não foram aplicadas. Isso ocorre mesmo que tenha sido realizada uma operação com garantia de aplicação das transações pendentes, porque a consulta pode estar em execução em uma réplica diferente da operação anterior.
  • O tempo das alterações simultâneas afeta os resultados das consultas não ancestrais. Se a princípio uma entidade satisfaz uma consulta, mas depois é alterada para que não satisfaça mais, ela ainda estará incluída no conjunto de resultados da consulta caso as alterações não tenham sido aplicadas aos índices na réplica em que a consulta foi executada.=

Estatísticas do Cloud Datastore

O Cloud Datastore mantém as estatísticas dos dados armazenados de um aplicativo, como o número de determinados tipos de entidades existentes ou o espaço usado por determinados tipos de valores de propriedade. Veja essas estatísticas na página painel do Cloud Datastore no Console do GCP. É possível também usar a API do Cloud Datastore para acessar esses valores com programação a partir do aplicativo. Basta consultar entidades com nomes especiais. Confira Estatísticas do Datastore no Java 8 para mais informações.

Esta página foi útil? Conte sua opinião sobre:

Enviar comentários sobre…

Ambiente padrão do App Engine para Java 8