O que é esta propriedade spring.jpa.open-in-view = true no Spring Boot?

121

Eu vi spring.jpa.open-in-view=truepropriedade na documentação do Spring Boot para configuração JPA.

  • É o truevalor padrão para esta propriedade se não for fornecido ?;
  • O que isso realmente faz? Não achei nenhuma boa explicação para isso;
  • Faz você usar em SessionFactoryvez de EntityManagerFactory? Se sim, como posso dizer para permitir que eu use EntityManagerFactory?

Obrigado!

Carlos Alberto
fonte

Respostas:

52

Esta propriedade registrará um OpenEntityManagerInViewInterceptor, que registra um EntityManagerno thread atual, portanto, você terá o mesmo EntityManageraté que a solicitação da web seja concluída. Não tem nada a ver com um Hibernate SessionFactoryetc.

Dunni
fonte
No momento, tenho o filtro OpenEntityManagerInViewFilter para controlar o EntityManager até que a solicitação da web seja concluída. Esse interceptor que você quis dizer "OpenEntityManagerInViewInterceptor" é o mesmo que "OpenEntityManagerInViewFilter"? Qual é a diferença entre eles? Então, eu não teria mais esse filtro no meu contexto de servlet para Spring Boot?
Carlos Alberto
1
O interceptor funciona apenas quando você usa o DispatcherServlet no Spring (porque o interceptor é um mecanismo do Spring). O filtro pode ser mapeado para todos os servlets configurados (nós o usamos para o FacesServlet em um de nossos aplicativos). Portanto, se você usar apenas o DispatcherServlet, poderá adicionar a propriedade e remover o filtro, caso contrário, use o filtro.
Dunni
298

O OSIV Anti-Padrão

Em vez de deixar a camada de negócios decidir como é melhor buscar todas as associações que são necessárias para a camada de Visualização, OSIV (Sessão Aberta na Visualização) força o Contexto de Persistência a permanecer aberto para que a camada de Visualização possa acionar a inicialização do Proxy, conforme ilustrado pelo diagrama a seguir.

insira a descrição da imagem aqui

  • O OpenSessionInViewFilterchama o openSessionmétodo do subjacente SessionFactorye obtém um novo Session.
  • O Sessionestá vinculado ao TransactionSynchronizationManager.
  • O OpenSessionInViewFilterchama doFilterda javax.servlet.FilterChainreferência do objeto e a solicitação é processada posteriormente
  • O DispatcherServleté chamado e encaminha a solicitação HTTP para o subjacente PostController.
  • O PostControllerchama o PostServicepara obter uma lista de Postentidades.
  • O PostServiceabre uma nova transação e HibernateTransactionManagerreutiliza a mesma Sessionque foi aberta pelo OpenSessionInViewFilter.
  • O PostDAObusca a lista de Postentidades sem inicializar qualquer associação preguiçosa.
  • O PostServiceconfirma a transação subjacente, mas Sessionnão é fechado porque foi aberto externamente.
  • O DispatcherServletcomeça a renderizar a IU, que, por sua vez, navega pelas associações lazy e aciona sua inicialização.
  • O OpenSessionInViewFilterpode fechar o Sessione 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ê vê 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 Connectioncomo 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 zombando da 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 @BatchSizeassociações de busca em lotes e FetchMode.SUBSELECTpara 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 é mantida durante toda a fase de renderização da IU, o que aumenta o tempo de concessão da conexão e limita o rendimento geral da transação devido ao congestionamento no conjunto de conexões 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.

Spring Boot e OSIV

Infelizmente, OSIV (Open Session in View) é habilitado por padrão no Spring Boot , e OSIV é realmente uma má ideia do ponto de vista de desempenho e escalabilidade .

Portanto, certifique-se de que, no application.propertiesarquivo de configuração, você tenha a seguinte entrada:

spring.jpa.open-in-view=false

Isso desabilitará o OSIV para que você possa lidar da LazyInitializationExceptionmaneira certa .

A partir da versão 2.0, o Spring Boot emite um aviso quando o OSIV está habilitado por padrão, para que você possa descobrir esse problema muito antes que ele afete um sistema de produção.

Para obter mais detalhes sobre OSIV, consulte este artigo .

Vlad Mihalcea
fonte
14
Há um AVISO sendo registrado atualmente.
Vlad Mihalcea
Isso se aplica ao Spring em geral ou apenas ao Spring Boot? Isso pode ser desabilitado por meio de uma classe anotada com @ Configuration em vez de definir uma propriedade?
Gordon
2
Só se aplica ao Spring Boot. No Spring padrão, você escolhe explicitamente quais beans usar ou se deseja um filtro da web, como OSIV. Não sei se você pode desativá-lo por meio de alguma anotação. Eu conheço apenas a definição de configuração.
Vlad Mihalcea
Não é um antipadrão. Tem impactos de desempenho, às vezes negativos, muitas vezes bastante neutros e de uma forma positiva em muitos casos: se você realmente quer uma relação preguiçosa para começar, você não precisa fazer a consulta em todos os casos e pode evitá-lo quando necessário, usando a visualização aberta.
ymajoros
5
De acordo com a Wikipedia, "Um antipadrão é uma resposta comum a um problema recorrente que geralmente é ineficaz e corre o risco de ser altamente contraproducente". Isso é exatamente o que é Open Session in View.
Vlad Mihalcea