Cos'è questa proprietà spring.jpa.open-in-view = true in Spring Boot?


121

Ho visto la spring.jpa.open-in-view=trueproprietà nella documentazione di Spring Boot per la configurazione JPA.

  • È il truevalore predefinito per questa proprietà se non è fornito affatto ?;
  • Cosa fa veramente questo? Non ho trovato alcuna buona spiegazione per questo;
  • Ti fa usare SessionFactoryinvece di EntityManagerFactory? Se sì, come posso dirgli di consentirmi di usarlo EntityManagerFactoryinvece?

Grazie!

Risposte:


52

Questa proprietà registrerà un OpenEntityManagerInViewInterceptor, che registra un EntityManageral thread corrente, quindi avrai lo stesso EntityManagerfino al termine della richiesta web. Non ha nulla a che fare con Hibernate SessionFactoryecc.


Al momento ho il filtro OpenEntityManagerInViewFilter per controllare EntityManager fino al termine della richiesta web. Questo intercettore che intendevi "OpenEntityManagerInViewInterceptor" è lo stesso di "OpenEntityManagerInViewFilter"? Qual è la differenza tra loro? Quindi, non avrei più questo filtro nel mio contesto servlet per Spring Boot?
Carlos Alberto

1
L'interceptor funziona solo quando si utilizza DispatcherServlet in Spring (poiché l'interceptor è un meccanismo Spring). Il filtro può essere mappato su tutti i servlet configurati (lo usiamo per FacesServlet in una delle nostre applicazioni). Quindi, se usi solo DispatcherServlet, puoi aggiungere la proprietà e rimuovere il filtro, altrimenti usa il filtro.
Dunni

300

L'OSIV Anti-Pattern

Invece di lasciare che il livello aziendale decida come è meglio recuperare tutte le associazioni necessarie dal livello di visualizzazione, OSIV (Open Session in View) forza il contesto di persistenza a rimanere aperto in modo che il livello di visualizzazione possa attivare l'inizializzazione del proxy, come illustrato dal diagramma seguente.

inserisci qui la descrizione dell'immagine

  • Il OpenSessionInViewFilterchiama il openSessionmetodo del sottostante SessionFactorye ottiene una nuova Session.
  • Il Sessionè legato al TransactionSynchronizationManager.
  • Le OpenSessionInViewFilterchiamate doFilterdel javax.servlet.FilterChainriferimento all'oggetto e la richiesta viene ulteriormente elaborata
  • La DispatcherServletsi chiama, e instrada la richiesta HTTP al sottostante PostController.
  • Le PostControllerchiamate i PostServiceper ottenere una lista di Postentità.
  • La PostServiceapre una nuova transazione, e lo HibernateTransactionManagerriutilizza lo stesso Sessionche è stato aperto dal OpenSessionInViewFilter.
  • Il PostDAOrecupera l'elenco delle Postentità senza inizializzare alcuna associazione pigra.
  • Il PostServicecommit della transazione sottostante, ma Sessionnon è chiuso perché è stato aperto esternamente.
  • Le DispatcherServletpartenze di rendering dell'interfaccia utente, che, a sua volta, naviga le associazioni pigri e fa scattare la loro inizializzazione.
  • Il OpenSessionInViewFiltergrado di chiudere la Session, e la connessione al database sottostante è rilasciato come pure.

A prima vista, questa potrebbe non sembrare una cosa terribile da fare, ma, una volta visualizzata dalla prospettiva di un database, una serie di difetti iniziano a diventare più evidenti.

Il livello di servizio apre e chiude una transazione di database, ma in seguito non è in corso alcuna transazione esplicita. Per questo motivo, ogni istruzione aggiuntiva emessa dalla fase di rendering dell'interfaccia utente viene eseguita in modalità di commit automatico. Il commit automatico mette sotto pressione il server del database perché ogni istruzione deve scaricare il log delle transazioni su disco, causando quindi molto traffico di I / O sul lato database. Un'ottimizzazione sarebbe contrassegnare Connectioncome di sola lettura, il che consentirebbe al server di database di evitare la scrittura nel log delle transazioni.

Non c'è più separazione delle preoccupazioni perché le istruzioni vengono generate sia dal livello di servizio che dal processo di rendering dell'interfaccia utente. La scrittura di test di integrazione che affermano il numero di istruzioni generate richiede il passaggio a tutti i livelli (Web, servizio, DAO) mentre l'applicazione viene distribuita su un contenitore Web. Anche quando si utilizza un database in memoria (ad esempio HSQLDB) e un server web leggero (ad esempio Jetty), questi test di integrazione saranno più lenti da eseguire rispetto a se i livelli fossero separati e i test di integrazione back-end usassero il database, mentre il i test di integrazione front-end deridevano del tutto il livello di servizio.

Il livello dell'interfaccia utente è limitato alla navigazione nelle associazioni che possono, a loro volta, attivare N + 1 problemi di query . Sebbene Hibernate offra il @BatchSizerecupero di associazioni in batch e FetchMode.SUBSELECTper far fronte a questo scenario, le annotazioni influenzano il piano di recupero predefinito, quindi vengono applicate a ogni caso d'uso aziendale. Per questo motivo, una query del livello di accesso ai dati è molto più adatta perché può essere adattata ai requisiti di recupero dei dati del caso d'uso corrente.

Ultimo ma non meno importante, la connessione al database viene mantenuta per tutta la fase di rendering dell'interfaccia utente, il che aumenta il tempo di lease della connessione e limita il throughput complessivo della transazione a causa della congestione nel pool di connessioni del database. Più la connessione viene mantenuta, più altre richieste simultanee attenderanno per ottenere una connessione dal pool.

Spring Boot e OSIV

Sfortunatamente, OSIV (Open Session in View) è abilitato per impostazione predefinita in Spring Boot e OSIV è davvero una cattiva idea dal punto di vista delle prestazioni e della scalabilità .

Quindi, assicurati application.propertiesdi avere la seguente voce nel file di configurazione:

spring.jpa.open-in-view=false

Questo disabiliterà OSIV in modo che tu possa gestirlo nel LazyInitializationExceptionmodo giusto .

A partire dalla versione 2.0, Spring Boot emette un avviso quando OSIV è abilitato per impostazione predefinita, quindi è possibile scoprire questo problema molto prima che influisca su un sistema di produzione.

Per maggiori dettagli su OSIV, consulta questo articolo .


14
Al giorno d'oggi viene registrato un avviso.
Vlad Mihalcea

Questo si applica a Spring in generale o solo a Spring Boot? Può essere disabilitato tramite una classe con annotazioni di configurazione @ invece di impostare una proprietà?
Gordon

2
Si applica solo a Spring Boot. Nella Spring standard, scegli esplicitamente quali bean utilizzare o se desideri un filtro web, come OSIV. Non so se puoi disabilitarlo tramite qualche annotazione. Conosco solo l'impostazione di configurazione.
Vlad Mihalcea

Non è un anti-pattern. Ha un impatto sulle prestazioni, a volte negativo, molte volte abbastanza neutro e in molti casi in modo positivo: se si desidera effettivamente una relazione pigra per cominciare, non è necessario eseguire la query in tutti i casi e puoi evitarlo quando necessario utilizzando open-in-view.
ymajoros

5
Secondo Wikipedia, "Un anti-pattern è una risposta comune a un problema ricorrente che di solito è inefficace e rischia di essere altamente controproducente". Questo è esattamente ciò che è Open Session in View.
Vlad Mihalcea
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.