Sessão aberta à vista no Spring Boot: a ameaça fantasma

Todos aqui estão certos, cada um à sua maneira e, portanto, todos aqui estão errados.
"O Conto dos Três" (A. e B. Strugatsky)

Se você usa o Spring Data JPA, depois de atualizar para o Spring Boot 2, ao iniciar o aplicativo, você poderá perceber um novo aviso no log:


O spring.jpa.open-in-view está ativado por padrão. Portanto, consultas ao banco de dados podem ser executadas durante a renderização da exibição. Configure explicitamente o spring.jpa.open-in-view para desativar esse aviso.

Neste artigo, tentarei explicar o que significa, quem é o culpado e o que fazer.


Para gerar um aplicativo completo no Spring Boot, apenas uma anotação @SpringBootApplication é @SpringBootApplication . Para tornar isso possível, a estrutura usa um grande número de configurações automáticas e configurações padrão. Além disso, para trabalhar fora da caixa, os desenvolvedores do Spring Boot tiveram que escolher alguns conceitos de desenvolvimento de aplicativos entre várias opções alternativas para cada um, para que o usuário não precisasse selecioná-los explicitamente. Por um lado, isso é bom para um início rápido e fácil desenvolvimento, mas, por outro lado, depois de um tempo, pode acontecer que algum conceito / paradigma / configuração padrão não seja adequado para o projeto, e muito trabalho será necessário para abandoná-lo. Um desses conceitos é o modo OSIV (Open Session In View) , que é incluído por padrão no Spring Boot.


Nesse modo, a sessão do Hibernate é mantida aberta o tempo todo em que a solicitação HTTP é processada, incluindo o estágio de criação da Visualização (recurso JSON ou página HTML). Isso possibilita o carregamento lento de dados na camada de apresentação após a confirmação de uma transação na camada de lógica de negócios. Por exemplo, solicitamos a entidade Article do banco de dados. O artigo deve ser exibido junto com os comentários. O OSIV permite que você chame simplesmente o método de entidade getComments() ao renderizar HTML, e os comentários serão carregados em uma solicitação separada. Quando o modo OSIV estiver desativado, obteremos uma LazyInitializationException , porque a sessão já está fechada e a entidade Article não é mais gerenciada pelo Hibernate. A maioria dos desenvolvedores do Hibernate encontrou uma LazyInitializationException ; O OSIV permite evitá-lo carregando dados conforme necessário em qualquer estágio do processamento da solicitação HTTP.


O OSIV no Spring Boot é implementado usando a OpenEntityManagerInViewInterceptor solicitações da web OpenEntityManagerInViewInterceptor . Ao contrário do Spring puro, aqui é ativado por padrão.


OSIV é considerado antipadrão. O melhor de tudo, o lado prejudicial de seu artigo foi explicado por Vlad Mihalcea, um dos desenvolvedores do Hibernate: A Sessão Aberta no Antipadrão de Exibição . Pontos-chave:


  • As consultas ao banco de dados sem uma transação funcionam no modo de confirmação automática, carregando muito.
  • Não há separação de responsabilidades, qualquer camada de aplicativo pode gerar consultas SQL, o que dificulta o teste.
  • Há um problema n + 1 quando cada coleção relacionada a uma entidade é carregada em uma solicitação separada.
  • As conexões longas com o banco de dados aumentam novamente a carga e reduzem a taxa de transferência.

Esses são problemas bastante desagradáveis ​​do modo OSIV e, ao que parece, fortes argumentos para não usá-lo. No entanto, em uma solicitação para desativá-lo por padrão , os desenvolvedores do Spring Boot também fizeram bons motivos para ativar o OSIV em novos projetos:


  • Compatibilidade com versões anteriores. Os aplicativos existentes ao atualizar para o Spring Boot 2 podem encontrar erros e bugs devido ao OSIV desativado. Para evitar isso, você só precisa definir o valor único spring.jpa.open-in-view , mas isso também dificulta a mudança para a nova versão.
  • A facilidade de uso para iniciantes e um início rápido são importantes para o Spring Boot. Se o OSIV estiver desativado, talvez não esteja claro para os iniciantes por que algo tão intuitivamente esperado como receber uma coleção de elementos relacionados ao acessar um método de entidade não funciona. Em vez disso, o usuário receberá uma LazyInitializationException , que diminuirá o caminho para um aplicativo em execução.
  • O OSIV permite aumentar a simplicidade do código, a usabilidade e a velocidade de desenvolvimento.
  • É difícil encontrar exemplos simples de como um aplicativo deve ser criado sem o OSIV.
  • Sem o OSIV, a camada de lógica de negócios precisa saber como os dados serão apresentados na interface do usuário, ou seja, qual DTO será necessário ou quais dados relacionados deverão ser carregados junto com a entidade raiz. Esta é novamente a ausência de uma divisão de responsabilidades.

Portanto, podemos distinguir duas visões sobre esse problema. Do ponto de vista do arquiteto de banco de dados (DBA), o Open Session In View é certamente inaceitável, pois a interação do aplicativo com o banco de dados não é idealmente organizada e causa um aumento de carga. Mas geralmente usamos soluções menos ideais para velocidade, facilidade de desenvolvimento e facilidade de ferramentas de aprendizado - escrevemos em idiomas gerenciados, usamos formatos de dados de texto para interação na rede e assim por diante. Da posição de um desenvolvedor de estrutura, para simplificar o desenvolvimento e o início rápido de iniciantes, o OSIV permite reduzir a carga cognitiva, o número de conceitos necessários para começar a desenvolver o aplicativo. Se o desenvolvedor escolheu o JPA, ele já concordou com alguma degradação do desempenho em troca da conveniência do desenvolvimento. A JPA ajuda a fazer amigos o modelo de dados objeto e relacional. Ao trabalhar no estilo de objeto para obter elementos relacionados, simplesmente recorremos ao método de entidade (mesmo que na camada de apresentação), que é simples, lógico e intuitivamente esperado, embora essa simplicidade seja enganadora.


Existem muitos exemplos e tutoriais para trabalhar no modo Abrir sessão no modo de exibição, a arquitetura como um todo é clara: a camada de serviço solicita uma entidade JPA, a camada de apresentação a serializa diretamente no JSON, por meio de um DTO intermediário, ou usa os dados para renderizar uma página HTML.


Menos claro é como trabalhar sem o OSIV. Um dos desenvolvedores do Spring no pedido mencionado reclama disso, eles dizem muitos gritos sobre o antipadrão, mas não existem exemplos simples de como viver sem ele. Nesta modalidade, as entidades podem ser usadas apenas para escrever e ler vários DTOs, separados para cada conjunto de dados na UI, que são mapeados diretamente do banco de dados. Ou consultas SQL personalizadas que descrevem a junção das coleções relacionadas necessárias para uma consulta da web específica. Ou seja, mais clichê e uma descrição das necessidades da interface do usuário na camada de lógica de negócios. Com o OSIV desativado, a abstração do JPA começa a fluir, o aplicativo descreve mais detalhes técnicos da interação com o banco de dados.


Assim, o desenvolvimento com OSIV é mais simples. Mas o problema é que, se no futuro você quiser abandoná-lo, precisará refazer muito, o conceito de trabalhar com o banco de dados no projeto, definindo uma propriedade, não poderá ser alterado. Pode ser necessário refazer toda a arquitetura do aplicativo. No entanto, abandonar o OSIV pode ser uma otimização prematura, que diminuirá a velocidade de desenvolvimento, o que pode ser crítico para uma inicialização, por exemplo. Você pode usar o OSIV e otimizar as consultas ao banco de dados apenas nos locais mais lentos. Por exemplo, a consulta de coleções de entidades sofre mais com o problema n + 1, quando cada entidade obtém várias consultas de coleções relacionadas.


Portanto, se você quiser fazer o que é certo, precisará desenvolver sem o OSIV. Mas se a velocidade do desenvolvimento e a simplicidade do código forem importantes, você poderá usar esse modo, resignado a alguma perda de desempenho.


O principal é que esse problema de desempenho não se transforma em uma enorme dívida técnica depois de alguns anos. É duplamente perigoso quando os desenvolvedores não suspeitam que essa dívida esteja se acumulando neles, porque o Spring Boot escolheu silenciosamente o conceito de Sessão Aberta à Vista para eles. Portanto, é excelente que, como resultado da solicitação acima mencionada, tenha sido decidido exibir no log um aviso sobre o modo usado, que citei no início do artigo.


Espero que o aviso e este artigo sobre ele ajudem os desenvolvedores a tomar uma decisão mais informada - sobre o uso do conceito de Open Session In View em um aplicativo no Spring Boot. Eu citei e discuti os principais argumentos a favor e contra, e também recomendo a leitura da discussão original. Esse problema mostra que um grande número de configurações automáticas e padrões no Spring / Spring Boot pode ser perigoso para desenvolvedores desatentos.


Você usa OSIV em aplicativos Spring Boot? Caso contrário, como está organizada a arquitetura para a interação da camada de apresentação com o banco de dados? Quais técnicas e / ou bibliotecas são usadas para isso?

Source: https://habr.com/ru/post/pt440734/


All Articles