Spring + Hibernate + Envers + multithreading - encerramento da sessão
-
21-12-2019 - |
Pergunta
Nós usamos o Hibernate (com JPA e Hibernate Envers persistir história de objetos.O aplicativo da web seja executado muitos segmentos, alguns deles são criados por RMI invocação de método a partir de outros aplicativos, alguns deles são criados pela própria aplicação e alguns deles são criados para lidar com solicitações http (que geram pontos de vista).
Nós também usamos a Sessão Aberta Na Visualização padrão para gerenciar sessões, de modo que a nossa web.xml contém:
<filter>
<filter-name>openEntityManagerInViewFilter</filter-name>
<filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>openEntityManagerInViewFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Banco de dados é acessado usando DAOs, todos eles têm EntityManagers injetado pela Primavera.
@PersistenceContext
protected EntityManager em;
@PersistenceUnit
protected EntityManagerFactory emf;
Tudo funcionou muito bem, antes de nós decidiu usar o Hibernate Envers.Quando qualquer segmento que não é uma vista de geração de thread que executa o código para obter uma versão antiga de um objeto, a exceção é lançada.
@Override
public O loadByRevision(Long revision, Long id) {
@SuppressWarnings("unchecked")
O object = (O) AuditReaderFactory.get(em).createQuery().forEntitiesAtRevision(getBaseClass(), revision.intValue())
.add(AuditEntity.id().eq(id)).getSingleResult();
return object;
}
Exception in thread "Programador" org.o hibernate.SessionException:Sessão é fechada!no org.o hibernate.interno.AbstractSessionImpl.errorIfClosed(AbstractSessionImpl.java:129) no org.o hibernate.interno.SessionImpl.createQuery(SessionImpl.java:1776) no org.o hibernate.envers.as ferramentas.consulta.QueryBuilder.toQuery(QueryBuilder.java:226) no org.o hibernate.envers.consulta.impl.AbstractAuditQuery.buildQuery(AbstractAuditQuery.java:92) no org.o hibernate.envers.consulta.impl.EntitiesAtRevisionQuery.(lista de EntitiesAtRevisionQuery.java:108) no org.o hibernate.envers.consulta.impl.AbstractAuditQuery.getSingleResult(AbstractAuditQuery.java:110) (...)
Quando o código acima é executado pela vista de geração de thread funciona bem.Além disso, o não-envers código DAO funciona bem para cada thread.Por exemplo, o trecho abaixo
@Override
public O load(Long id) {
final O find = em.find(getBaseClass(), id);
return find;
}
pode ser executado através de RMI fios, sem problemas.
Por que não ver os tópicos chamada de métodos na entidade gestora, sem exceções, mas não pode usar Envers' AuditReaderFactory com a entidade manager?Eu pensei que talvez chamar um método em que a entidade manager cria uma sessão temporária, mas que não acontece quando usando o Envers, é verdade?
Qual é a melhor maneira de corrigir esse problema (para que o AuditReaderFactory pode ser usado de cada segmento)?
Solução
Nós não descobrimos o porquê de, em não-segmentos de interface do usuário chamadas de método em EntityManagerFactory
funcionou, mas chamadas de método em AuditReaderFactory
não.De qualquer maneira, nós encontramos uma maneira de corrigi-lo.
A solução foi anotar métodos com @Transactional
.Se qualquer método na cadeia de chamada antes da chamada para o AuditReaderFactory foi marcado como @Transactional
, não houve SessionException
não segmentos de interface do usuário.
Descobriu-se que fazer loadByRevision
transacional não foi suficiente.Se um objeto retornado por esse método contido lenta carregado persistente de bolsas, o acesso a eles fora do loadByRevision
escopo do método causados LazyInitializationException
(não houve sessão).
A solução final foi para certificar-se de que, se qualquer segmento deseja carregar alguns dados do banco de dados, todo o carregamento (um objeto e acessar lenta carregado coleções) vai ser feito dentro de um método anotado com @Transactional
.