2013-03-26 16 views
11

Sto usando JDBC per parlare con il mio database Postgres. Se tutta la mia app scappa da una singola connessione, cioè c'è sempre una sola chiamata a;JDBC Transaction vs Connection Chiarimento

DriverManager.getConnection("jdbc:postgresql://host:5432/database", user, pass); 

Ma questo oggetto Connection è condiviso tra più thread in Java, ho ragione nel ritenere che qualsiasi tentativo di utilizzare le transazioni SQL (BEGIN e COMMIT di stile) è solo andare a essere molto confusa e di rotture, data la potenziale per interleave dei thread Java? L'oggetto Connection 'sa' quale thread Java lo sta usando per fare interrogazioni?

Devo avere un oggetto Connection per thread Java e utilizzare le transazioni SQL in questo modo? O dovrei eseguire tutto il mio isolamento transazionale in Java usando synchronized?

+1

Sfrutta il tuo problema e usa [JDBC Connection Pooling] (http://stackoverflow.com/q/2835090/1065197) –

risposta

10

Giusto per approfondire le risposte esistenti:

PgJDBC's Connection object is thread-safe, ma solo su un livello di istruzione. Non si arresta in modo anomalo o genera risultati errati se utilizzato da più thread in modalità di autocommit, ma non isola le transazioni di thread diversi per te.Come per la documentazione è necessario utilizzare un pool di connessioni per questo.

Ci sono in realtà molti modi per utilizzare le connessioni tra più thread:

  • Utilizzare un pool di connessione interna in cui si recupera le connessioni da, eseguire il lavoro con loro, e restituirli alla piscina. Questa è l'opzione fortemente preferibile per la maggior parte delle applicazioni. Esistono molte implementazioni del pool di connessioni JDBC per Java, quindi non eseguire il rollover. dbcp e c3p0 sono due implementazioni popolari, ma se si utilizza un ambiente servlet o un server di app, in genere si dovrebbe utilizzare il pool di connessioni del server anziché portarlo da solo.

  • Utilizzare un pool di connessione esterno come pgbouncer o pgpool-II e aprire/chiudere le connessioni ad esso liberamente. Questo è leggermente più lento ed è per lo più un'opzione utilizzata dove l'applicazione non può o per vari motivi non deve raggruppare le connessioni internamente. Probabilmente non è necessario farlo a meno che non sia necessario limitare i conteggi totali delle connessioni al DB e condividerli tra più applicazioni o istanze di app.

  • Non utilizzare pool e aprire/chiudere connessioni liberamente. Questo è terribilmente inefficiente. Non farlo

  • Mantieni una connessione per thread utilizzando la memoria locale del thread. Funzionerà, ma è gravemente inefficiente perché ogni connessione aperta lega le risorse del server di database mentre è inattiva. Non farlo a meno che non si utilizzi un pool di connessione esterno come PgBouncer in modalità pooling delle transazioni, nel qual caso è OK.

  • Utilizzare solo una singola connessione e concludere le transazioni nei blocchi synchronized, sincronizzando l'istanza Connection. Funzionerà e utilizzerà la connessione al database in modo efficiente, ma limiterà le prestazioni dei thread. Generalmente non è un buon design per niente tranne le app giocattolo/comodità.

  • Utilizzare solo una singola connessione con il proprio thread dedicato. Altre connessioni passano strutture di dati che descrivono il lavoro da fare su quel thread tramite una coda FIFO, stile produttore/consumatore. Questo funziona se i thread trascorrono la maggior parte del loro tempo a svolgere un lavoro pesante con CPU o altri database e richiedono solo un accesso limitato al database. Praticamente l'unica ragione per usarlo invece di usare un pool di connessioni è se sei costretto a utilizzare una singola connessione per qualche motivo esterno, ma se lo sei allora può essere un'opzione decente.

In generale, tuttavia, è sufficiente utilizzare un pool di connessioni e utilizzarlo.

+0

Grazie di tutto, grazie, hai confermato molto di quello che credevo ma non mi era mai stato detto. – lynks

4

ho ragione nel ritenere che qualsiasi tentativo di utilizzare le transazioni SQL (BEGIN e COMMIT stile) è solo andare a essere molto confusa e di rotture, dato il potenziale per i thread Java per interleave?

Questo è assolutamente giusto.

L'oggetto Connection 'sa' quale thread Java lo sta utilizzando per effettuare query?

No, non è così.

Devo avere un oggetto Connection per thread Java e utilizzare le transazioni SQL in questo modo?

Sì, questo è un modo per farlo. Il lato negativo dell'allocazione "connessione per thread" è potenzialmente in grado di aprire più connessioni di quelle necessarie, portando a un utilizzo non ottimale delle risorse. È anche possibile aprire una connessione solo quando il thread ne ha bisogno e chiuderla una volta che il thread è stato eseguito con l'accesso RDBMS. Se segui questo percorso, assicurati di utilizzare un pool di connessioni per ridurre il sovraccarico di riapertura delle connessioni più volte.

+0

Grazie, penso di averlo nella mia testa, ho un'app che sembra mescolare java metodi di isolamento della transazione con metodi sql e talvolta viene generata una connessione mid-thread, altre volte viene utilizzata una connessione globale. Sposterò tutto questo in un pool di connessioni :) – lynks

+1

Minor selezionamento: in realtà, l'oggetto 'Connection' di Java * non sa quale thread lo sta usando per fare query in un dato momento; 'Thread.currentThread()'. Semplicemente non gli importa e si aspetta che i thread coordinino il loro lavoro da soli. Sarebbe del tutto possibile scrivere una Connection che usasse più connessioni PostgreSQL sottostanti per fare sessioni locali thread, ma inutilmente complesse quando si può fare la stessa cosa usando singoli oggetti Connection e meccanismi locali thread-esistenti o semplicemente usare un pool di connessioni. –

2
Does the Connection object 'know' which Java thread is using it to make queries? 

No, l'oggetto di connessione non sa quale thread java lo sta utilizzando.

Devo avere un oggetto Connection per thread Java e utilizzare le transazioni SQL in questo modo? O dovrei eseguire tutto il mio isolamento transazionale in Java usando sincronizzato?

Dovremmo utilizzare l'origine dati del pool di connessione jdbc specifica del database per eseguire la transazione, in modo che quando un oggetto di connessione non è di uso, la connessione tornerà al pool senza essere eliminata. In questo modo, il server delle applicazioni può ottimizzare le prestazioni di inizializzazione della connessione.

Inoltre, è necessario utilizzare la chiamata al metodo sincronizzato durante l'operazione di aggiornamento, poiché ciò renderà un'operazione molto più sicura nella produzione.

+0

Ciao, grazie per la risposta. Potresti chiarire cosa intendi per l'ultimo bit? Non è sufficiente racchiudere il mio set di query nelle query 'BEGIN' e' COMMIT'? Qual è la ragione per aggiungere un meccanismo di isolamento Java in primo piano? – lynks

+0

Tranne Oracle Database, nessun altro database non esegue il blocco a livello di riga durante la transazione per impostazione predefinita. Quindi è sicuro usare il metodo sincronizzato, perché qui tutti gli aggiornamenti verranno elaborati in coda. Grazie –