Este tópico descreve como as APIs de consulta do eXtreme Scale e o plug-in de indexação MapRangeIndex interagem com bloqueios e algumas boas práticas para aumentar a concorrência e diminuir os conflitos ao usar a estratégia de bloqueio pessimista para mapas.
A API de Consulta do ObjectGrid permite consultas SELECT sobre objetos e entidades de cache do ObjectMap. Quando uma consulta é executada, o mecanismo de consulta utiliza um MapRangeIndex quando possível para localizar chaves correspondentes na cláusula WHERE da consulta ou para vincular relacionamentos. Quando um índice não está disponível, o mecanismo de consulta varrerá cada entrada em um ou mais mapas para localizar as entradas apropriadas. O mecanismo de consulta e os plug-ins de índice adquirirão bloqueios para verificar dados consistentes, dependendo da estratégia de bloqueio, nível de isolamento de transação e estado da transação.
O plug-in HashIndex do eXtreme Scale permite localizar chaves baseadas em um único atributo armazenado no valor de entrada do cache. O índice armazena o valor indexado em uma estrutura de dados separada do mapa de cache. O índice valida as chaves em relação a entradas de mapa antes de retornar para o usuário para tentar alcançar um conjunto de resultados exato. Quando a estratégia de bloqueio pessimista é utilizada e o índice é utilizado junto a uma instância local do ObjectMap (versus um ObjectMap do cliente/servidor), o índice adquirirá bloqueios para cada entrada correspondente. Ao utilizar o bloqueio optimistic ou um ObjectMap remoto, os bloqueios são sempre liberados imediatamente.
O tipo de bloqueio que é adquirido depende do argumento forUpdate passado para o método ObjectMap.getIndex. O argumento forUpdate especifica o tipo de bloqueio que o índice deve adquirir. Se false, um bloqueio compartilhável (S) é adquirido e se true, um bloqueio atualizável (U) é adquirido.
Se o tipo de bloqueio for compartilhável, a configuração de isolamento de transação para a sessão é aplicada e afeta a duração do bloqueio. Consulte o tópico Isolamento de Transação para obter detalhes sobre como o nível de isolamento é utilizado para incluir simultaneidade nos aplicativos.
O mecanismo de consulta do eXtreme Scale adquire bloqueios S quando necessário para introspectar as entrada do cache para descobrir se elas satisfazem os critérios de filtro da consulta. Ao utilizar o isolamento de transação de leitura repetível com bloqueio pessimistic, os bloqueios S são retidos apenas para os elementos que estão incluídos no resultado da consulta e não são incluídos no resultado. Se utilizando um nível de isolamento de transação inferior ou o bloqueio optimistic, os bloqueios S não são retidos.
Ao usar a consulta do eXtreme Scale a partir de um cliente, a consulta tipicamente é executada no servidor, a menos que todos os mapas ou entidades referenciadas na consulta sejam locais para o cliente (por exemplo: um mapa replicado pelo cliente ou uma entidade de resultado da consulta). Todas as consultas que são executadas em uma transação de leitura/gravação reterão bloqueios S, conforme descrito na seção anterior. Se a transação não for uma transação de leitura/gravação, então, uma sessão não será retida no servidor e os bloqueios S serão liberados.
Bloqueios compartilháveis são úteis quando a simultaneidade e a consistência são importantes. Isto garante que um valor de entrada não seja alterado durante a duração da transação. Nenhuma outra transação pode alterar o valor enquanto qualquer outro bloqueio S é mantido, e apenas uma outra transação possa estabelecer uma tentativa de atualizar a entrada. Consulte o tópico Modo de Bloqueio Pessimistic para obter mais detalhes sobre os modos S, U e X.
Bloqueios atualizáveis são utilizados para identificar a tentativa de atualizar uma entrada de cache ao utilizar a estratégia de bloqueio pessimistic. Isto permite a sincronização entre transações que desejam modificar uma entrada de cache. As transações ainda podem visualizar a entrada utilizando um bloqueio S, mas outras transações são impedidas de adquirir um bloqueio U ou um bloqueio X. Em muitos cenários, adquirir um bloqueio U sem primeiro adquirir um bloqueio S é necessário para evitar conflitos. Consulte o tópico Modo de Bloqueio Pessimistic para obter exemplos de conflitos comuns.
ObjectMap orderMap = session.getMap("Order");
ObjectQuery q = session.createQuery("SELECT o FROM Order o WHERE o.orderDate=?1");
q.setParameter(1, "20080101");
q.setForUpdate(true);
session.begin();
// Run the query. Each order has U lock
Iterator result = q.getResultIterator();
// For each order, update the status.
while(result.hasNext()) {
Order o = (Order) result.next();
o.status = "shipped";
orderMap.update(o.getId(), o);
}
// When committed, the
session.commit();
Query q = em.createQuery("SELECT o FROM Order o WHERE o.orderDate=?1");
q.setParameter(1, "20080101");
q.setForUpdate(true);
emTran.begin();
// Run the query. Each order has U lock
Iterator result = q.getResultIterator();
// For each order, update the status.
while(result.hasNext()) {
Order o = (Order) result.next();
o.status = "shipped";
}
tmTran.commit();
Quando o atributo setForUpdate está ativado, a transação é automaticamente convertida em uma transação de leitura/gravação e os bloqueios são mantidos no servidor, conforme esperado. Se a consulta não puder utilizar nenhum índice, então, o mapa deve ser varrido, o que resultará em bloqueios U temporários para entradas de mapas que não satisfazem o resultado da consulta, e bloqueios U para as entradas que estão incluídas no resultado.