Para obter uma descrição mais detalhada, você pode ler meu artigo Abrir sessão no antipadrão de visualização . Caso contrário, aqui está um resumo de porque você não deve usar Open Session In View.
Open Session In View tem uma abordagem inadequada para buscar dados. Em vez de permitir que a camada de negócios decida como é melhor buscar todas as associações que são necessárias para a camada de Visualização, ela força o Contexto de Persistência a permanecer aberto para que a camada de Visualização possa acionar a inicialização do Proxy.
- O
OpenSessionInViewFilter
chama o openSession
método do subjacente SessionFactory
e obtém um novo Session
.
- O
Session
está vinculado ao TransactionSynchronizationManager
.
- O
OpenSessionInViewFilter
chama doFilter
da javax.servlet.FilterChain
referência do objeto e a solicitação é processada posteriormente
- O
DispatcherServlet
é chamado e encaminha a solicitação HTTP para o subjacente PostController
.
- O
PostController
chama PostService
para obter uma lista de Post
entidades.
- O
PostService
abre uma nova transação e HibernateTransactionManager
reutiliza a mesma Session
que foi aberta pelo OpenSessionInViewFilter
.
- O
PostDAO
busca a lista de Post
entidades sem inicializar nenhuma associação preguiçosa.
- O
PostService
confirma a transação subjacente, mas Session
não é fechado porque foi aberto externamente.
- O
DispatcherServlet
começa a renderizar a IU, que, por sua vez, navega pelas associações lazy e dispara sua inicialização.
- O
OpenSessionInViewFilter
pode fechar o Session
e a conexão de banco de dados subjacente também é liberada.
À primeira vista, pode não parecer uma coisa terrível de se fazer, mas, uma vez que você visualiza da perspectiva do banco de dados, uma série de falhas começa a se tornar mais óbvia.
A camada de serviço abre e fecha uma transação de banco de dados, mas depois disso, não há nenhuma transação explícita acontecendo. Por esse motivo, cada instrução adicional emitida na fase de renderização da IU é executada no modo de confirmação automática. A confirmação automática pressiona o servidor de banco de dados porque cada instrução deve liberar o log de transações para o disco, causando, portanto, muito tráfego de E / S no lado do banco de dados. Uma otimização seria marcar o Connection
como somente leitura, o que permitiria ao servidor de banco de dados evitar a gravação no log de transações.
Não há mais separação de interesses porque as instruções são geradas tanto pela camada de serviço quanto pelo processo de renderização da IU. Escrever testes de integração que afirmam o número de instruções que estão sendo geradas requer passar por todas as camadas (web, serviço, DAO), enquanto o aplicativo é implantado em um contêiner da web. Mesmo ao usar um banco de dados na memória (por exemplo, HSQLDB) e um servidor web leve (por exemplo, Jetty), esses testes de integração serão mais lentos para executar do que se as camadas fossem separadas e os testes de integração de back-end usassem o banco de dados, enquanto o Os testes de integração front-end estavam simulando a camada de serviço como um todo.
A camada de IU é limitada a associações de navegação que podem, por sua vez, acionar N + 1 problemas de consulta. Embora o Hibernate ofereça @BatchSize
associações de busca em lotes e FetchMode.SUBSELECT
para lidar com este cenário, as anotações estão afetando o plano de busca padrão, portanto, são aplicadas a todos os casos de uso de negócios. Por esse motivo, uma consulta da camada de acesso a dados é muito mais adequada porque pode ser adaptada aos requisitos atuais de busca de dados do caso de uso.
Por último, mas não menos importante, a conexão com o banco de dados pode ser mantida durante toda a fase de renderização da IU (dependendo do modo de liberação da conexão), o que aumenta o tempo de concessão da conexão e limita o rendimento geral da transação devido ao congestionamento no pool de conexão do banco de dados. Quanto mais a conexão for mantida, mais outras solicitações simultâneas irão esperar para obter uma conexão do pool.
Portanto, ou você obtém a conexão mantida por muito tempo, ou adquire / libera várias conexões para uma única solicitação HTTP, colocando pressão no pool de conexão subjacente e limitando a escalabilidade.
Spring Boot
Infelizmente, Open Session in View é habilitado por padrão no Spring Boot .
Portanto, certifique-se de que, no application.properties
arquivo de configuração, você tenha a seguinte entrada:
spring.jpa.open-in-view=false
Isso desabilitará o OSIV, para que você possa lidar da LazyInitializationException
maneira certa .