2012-05-19 9 views
11

Sto usando Hibernate con Spring su Tomcat. Ho letto e riletto spesso l'argomento JBoss wiki page sull'argomento e questo è stato utile. Ma mi lascia con alcune domande.Hibernate Open Session in View: Transaction per Request?

  1. L'idea di avviare una transazione per ogni richiesta mi turba. Immagino di poter limitare il filtro a certi controller, magari mettendo tutti i miei controller che hanno bisogno di una transazione sotto un percorso pseudo "tx" o qualcosa del genere. Ma non è una cattiva idea usare le transazioni se non sai se ne avrai bisogno? E se sto solo leggendo alcune richieste - si legge che molto probabilmente potrebbero provenire da una cache - non sto meglio senza una transazione?

  2. Ho letto post che menzionano come hanno gestito le transazioni a livello di servizio, e mi piacerebbe farlo con Spring. Ma allora come appare il codice del filtro? Voglio comunque che la sessione sia disponibile a mio avviso per un caricamento lento.

  3. Se tutto ciò che devo fare è chiamare il sessionFactory.getCurrentSession() nel mio filtro, come viene "liberato" di nuovo alla fabbrica di sessione per il riutilizzo? (Mi aspettavo di vedere uno session.close() o qualcosa del genere, anche quando si usano le transazioni.) Chi sta dicendo alla fabbrica della sessione che quella sessione può essere riutilizzata?

  4. Forse è la chiamata beginTransaction() che associa una data connessione di database a una data sessione per la durata di una richiesta? Altrimenti, una sessione estrae le connessioni db dal pool, se necessario, giusto?

Grazie per la vostra pazienza con tutte le mie domande.

(E se la tua risposta sarà un link alla documentazione di Spring, mi farai piangere, non vuoi, vero? Pagherò soldi veri se la gente smetterebbe di rispondere a Spring in questo senso.)

risposta

20

Le tue preoccupazioni sono valide, la soluzione fornita nella pagina wiki è troppo semplicistica. La transazione non deve essere gestita a livello web, ma deve essere gestita a livello di servizio.

L'implementazione corretta apre una sessione e la associa a un thread nel filtro. Nessuna transazione è iniziata. La sessione viene messa in modalità flush mai - sola lettura. Una chiamata di servizio imposta la sessione sulla modalità flush automatica & avvia/esegue il commit della transazione. Una volta che il metodo di servizio termina, la modalità di risciacquo della sessione viene ripristinata in mai.

C'è anche un'opzione per non aprire la sessione nel filtro. Ogni chiamata del livello di servizio aprirebbe una transazione separata & - dopo che la chiamata di servizio è stata completata, la sessione non è chiusa, ma registrata per la chiusura differita. La sessione verrà chiusa una volta completata l'elaborazione della richiesta web.

Spring fornisce OpensessionInViewFilter che funziona come descritto sopra. Quindi ignora l'articolo di jboss wiki e configura semplicemente OpensessionInViewFilter: tutto andrà bene.

SessionFactory.getCurrentSession() - crea e assegna internamente la sessione a un thread locale. Ogni richiesta/thread avrà una sua sessione. Una volta completata l'elaborazione della richiesta web, la sessione verrà chiusa. Dall'interno del tuo codice hai solo bisogno di usare SessionFactory.getCurrentSession() e non devi chiuderlo. L'esempio di codice nella pagina wiki di jboss è errato - dovrebbe avere un SessionFactory.getCurrentSession(). Close() nel blocco finally.Oppure potrebbero utilizzare la transazione JTA e configurare l'ibernazione per aprire/chiudere la sessione insieme alla transazione JTA.

+0

Sono andato da qui a lì e poi a lì, saltando sul web su questo argomento per una settimana ... ed è la prima volta che ho letto che Spring ha un filtro OpenSessionInView. Grazie. – Marvo

+0

L'uomo, che funziona così bene. Grazie! – Marvo

+0

Ho sempre pensato che avrebbe funzionato come una transazione. Ma in realtà la transazione è limitata da SpringTransactional. Grazie per la spiegazione. –

0

Non è un problema se il filtro crea una sessione per ogni richiesta, poiché le sessioni provengono da un pool di sessioni e verranno riutilizzate. Dal punto di vista del sistema operativo, non succede nulla.

Una sessione di sospensione è, di fatto, una connessione tcp (o socket/pipe) al server di database. Il costo della creazione di db conn è molto dipendente dal tipo sql (postgresql è notevolmente negativo in questo, sebbene sia molto buono in ogni cosa). Ma non significa davvero nulla, perché l'ibernazione riutilizza le connessioni del database.

La semplice soluzione di filtro Hibernate avvia una nuova transazione sulla sessione per ogni richiesta. È una transazione dalla vista di SQL: è una query "BEGIN" e "COMMIT". È sempre costoso e dovrebbe essere ridotto.

IMHO una possibile soluzione erano, se le transazioni sono state avviate solo alla prima query della richiesta corrente. Forse la primavera ha qualcosa di utile per questo.

+1

Ciò che è arrivato è utilizzare il filtro OpenSessionInView (vedere sopra) in combinazione con l'annotazione Spring @Transactional. Finora, funziona alla grande. – Marvo

+0

@ Marvo Non ho avuto una buona esperienza con questo. Non hai il controllo, cosa succede esattamente e perché. Nel mio ultimo progetto ho avuto più connessioni al database (alcune entità che collegano il primo, un po 'al secondo) con cross-directing spring layer, e alcuni dei processi sono stati avviati da Quartz, alcuni dal web. La situazione era complessa e il problema principale consisteva nel fatto che in una cosa basata su annotazione o/e AOP si controlla molto da vicino, cosa è fallito o dove si trova il problema. Funziona semplicemente o no, ma non puoi vederli. In un ambiente procedurale chiaro è banale. – peterh