Eu recomendo adicionar um
@Startup @Singleton classe que estabelece uma conexão JDBC com o banco de dados PostgreSQL e usa LISTEN e NOTIFY para lidar com a invalidação de cache. Atualizar :Aqui está outra abordagem interessante, usando pgq e uma coleção de trabalhadores para invalidação.
Sinalização de invalidação
Adicione um gatilho na tabela que está sendo atualizada que envia um
NOTIFY sempre que uma entidade é atualizada. No PostgreSQL 9.0 e acima, este NOTIFY pode conter uma carga útil, geralmente um ID de linha, para que você não precise invalidar todo o cache, apenas a entidade que foi alterada. Em versões mais antigas em que uma carga útil não é suportada, você pode adicionar as entradas invalidadas a uma tabela de log com carimbo de data/hora que sua classe auxiliar consulta quando recebe um NOTIFY , ou apenas invalidar todo o cache. Sua classe auxiliar agora
LISTEN s no NOTIFY eventos que o gatilho envia. Quando recebe um NOTIFY evento, ele pode invalidar entradas de cache individuais (veja abaixo) ou liberar todo o cache. Você pode escutar notificações do banco de dados com o suporte escutar/notificar do PgJDBC. Você precisará desempacotar qualquer pool de conexão gerenciado java.sql.Connection para obter a implementação subjacente do PostgreSQL para que você possa convertê-la em org.postgresql.PGConnection e chame getNotifications() nele. Uma alternativa para
LISTEN e NOTIFY , você pode pesquisar uma tabela de log de alterações em um cronômetro e ter um gatilho na tabela de problemas anexando IDs de linha alterados e carimbos de data/hora de alteração à tabela de log de alterações. Essa abordagem será portátil, exceto pela necessidade de um gatilho diferente para cada tipo de banco de dados, mas é ineficiente e menos oportuna. Isso exigirá pesquisas ineficientes frequentes e ainda terá um atraso de tempo que a abordagem de escuta/notificação não possui. No PostgreSQL você pode usar um UNLOGGED tabela para reduzir um pouco os custos dessa abordagem. Níveis de cache
EclipseLink/JPA tem alguns níveis de cache.
O cache de 1º nível está no
EntityManager nível. Se uma entidade estiver anexada a um EntityManager por persist(...) , merge(...) , find(...) , etc, então o EntityManager é necessário retornar a mesma instância dessa entidade quando ele é acessado novamente na mesma sessão, independentemente de seu aplicativo ainda ter referências a ele. Esta instância anexada não será atualizada se o conteúdo do banco de dados tiver sido alterado. O cache de 2º nível, que é opcional, está no
EntityManagerFactory level e é um cache mais tradicional. Não está claro se você tem o cache de 2º nível ativado. Verifique seus logs do EclipseLink e seu persistence.xml . Você pode obter acesso ao cache de 2º nível com EntityManagerFactory.getCache(); veja Cache . @thedayofcondor mostrou como liberar o cache de 2º nível com:
em.getEntityManagerFactory().getCache().evictAll();
mas você também pode despejar objetos individuais com o
evict(java.lang.Class cls, java.lang.Object primaryKey) ligar:em.getEntityManagerFactory().getCache().evict(theClass, thePrimaryKey);
que você pode usar em seu
@Startup @Singleton NOTIFY listener para invalidar apenas as entradas que foram alteradas. O cache de 1º nível não é tão fácil, pois faz parte da lógica da sua aplicação. Você vai querer saber como o
EntityManager , entidades anexadas e destacadas, etc funcionam. Uma opção é sempre usar entidades desanexadas para a tabela em questão, onde você usa um novo EntityManager sempre que você buscar a entidade. Essa questão:Invalidando a sessão do JPA EntityManager
tem uma discussão útil sobre como lidar com a invalidação do cache do gerenciador de entidade. No entanto, é improvável que um
EntityManager cache é o seu problema, porque um serviço da Web RESTful geralmente é implementado usando o curto EntityManager sessões. É provável que isso seja um problema apenas se você estiver usando contextos de persistência estendidos ou se estiver criando e gerenciando seu próprio EntityManager sessões em vez de usar persistência gerenciada por contêiner.