Como manter a consistência do cache do Hibernate executando dois aplicativos Java?

StackOverflow https://stackoverflow.com/questions/48733

  •  09-06-2019
  •  | 
  •  

Pergunta

Nosso design possui um jvm que é um jboss/webapp (leitura/gravação) que é usado para manter os dados via hibernação (usando jpa) no banco de dados.O modelo possui de 10 a 15 classes persistentes com 3 a 5 níveis de profundidade nos relacionamentos.

Temos então uma jvm separada que é o servidor que usa esses dados.Como está sendo executado continuamente, temos apenas uma longa sessão de banco de dados (somente leitura).

Atualmente não há cache intra-jvm envolvido - portanto, sinalizamos manualmente um jvm do outro.

Agora, quando o webapp altera alguns dados, ele sinaliza ao servidor para recarregar os dados alterados.O que descobrimos é que precisamos dizer ao hibernate para limpar os dados e depois recarregá-los.Apenas fazer uma busca/mesclagem com o banco de dados não funciona - principalmente em relação aos objetos várias camadas abaixo na hierarquia.

Alguma ideia sobre se há algo fundamentalmente errado com esse design ou se alguém está fazendo isso e teve mais sorte trabalhando com o hibernate nas recargas.

Obrigado, Chris

Foi útil?

Solução

Uma sessão do Hibernate carrega todos os dados que lê do banco de dados no que eles chamam de cache de primeiro nível.Depois que uma linha é carregada do banco de dados, qualquer busca subsequente de uma linha com o mesmo PK retornará os dados desse cache.Além disso, as garantias do Hibernate fazem referência à igualdade para objetos com o mesmo PK em uma única sessão.

Pelo que entendi, seu aplicativo de servidor somente leitura nunca fecha a sessão do Hibernate.Portanto, quando o banco de dados é atualizado pelo aplicativo de leitura e gravação, a sessão no servidor somente leitura não tem conhecimento da alteração.Efetivamente, seu aplicativo somente leitura está carregando uma cópia do banco de dados na memória e usando essa cópia, que fica obsoleta no devido tempo.

A melhor e mais simples ação que posso sugerir é fechar e abrir sessões conforme necessário.Isso contorna todo o problema.As sessões do Hibernate pretendem ser uma janela para uma interação de curta duração com o banco de dados.Concordo que há um ganho de desempenho ao não recarregar o gráfico do objeto repetidas vezes;mas você precisa medir e se convencer de que vale a pena.

Outra opção é fechar e reabrir a Sessão periodicamente.Isso garante que o aplicativo somente leitura funcione com dados que não sejam mais antigos que um determinado intervalo de tempo.Mas definitivamente há uma janela onde o aplicativo somente leitura funciona com dados obsoletos (embora o design garanta que ele eventualmente obterá os dados atualizados).Isso pode ser permitido em muitas aplicações – você precisa avaliar sua situação.

A terceira opção é usar um cache de segundo nível implementação e usar sessões de curta duração.Existem vários pacotes de cache que funcionam com o Hibernate com méritos e deméritos relativos.

Outras dicas

Chris, estou um pouco confuso sobre suas circunstâncias.Se bem entendi, você tem um aplicativo da web (leitura/gravação) e um aplicativo independente (somente leitura?) Usando o Hibernate para acessar um banco de dados compartilhado.As alterações feitas no aplicativo Web não são visíveis para o aplicativo independente.Isso está certo?

Em caso afirmativo, você considerou usar uma implementação de cache de segundo nível diferente?Estou me perguntando se você pode usar um cache clusterizado compartilhado pelo aplicativo da Web e pelo aplicativo independente.Acredito que o SwarmCache, que está integrado ao Hibernate, permitirá isso, mas ainda não tentei.

Em geral, porém, você deve saber que o conteúdo de um determinado cache nunca estará ciente da atividade de outro aplicativo (é por isso que sugiro que ambos os aplicativos compartilhem um cache).Boa sorte!

Do meu ponto de vista, você deve alterar o cache sublinhado do Hibernate para aquele que suporta o modo clusterizado.Poderia ser um Cache JBoss ou um Esconderijo do Enxame.O primeiro possui melhor suporte à sincronização de dados (replicação e invalidação) e também suporta JTA.

Então você poderá configurar a sincronização de cache entre webapp e servidor.Observe também o nível de isolamento se você usar o JBoss Cache.Eu acredito que você deveria usar READ_COMMITTED modo se desejar obter novos dados em um servidor da mesma sessão.

A prática mais utilizada é ter um Gerenciador de entidades gerenciadas por contêiner para que dois ou mais aplicativos no mesmo contêiner (ou seja, Glassfish, Tomcat, Websphere) possam compartilhar os mesmos caches.Mas se você não usa um contêiner de Aplicativo, porque usa o Play!por exemplo, então eu construiria alguns webservices no Aplicativo principal para ler/gravar consistentemente no cache.

Acho que usar dados obsoletos é uma porta aberta para o desastre.Assim como os Singletons se tornam Multitons, os aplicativos somente leitura costumam ser um escreva às vezes.

Cinto e suspensórios :)

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top