Domanda

Qual è il modo migliore per gestire una connessione al database in un servlet Java?

Attualmente, apro semplicemente una connessione nella funzione init () , quindi la chiudo in destroy () .

Tuttavia, sono preoccupato che "permanentemente". trattenere una connessione al database potrebbe essere una cosa negativa.

È questo il modo corretto di gestirlo? In caso contrario, quali sono alcune opzioni migliori?

modifica: per dare un po 'più di chiarimenti: ho provato semplicemente ad aprire / chiudere una nuova connessione per ogni richiesta, ma con i test ho riscontrato problemi di prestazioni dovuti alla creazione di troppe connessioni.

C'è qualche valore nel condividere una connessione su più richieste? Le richieste per questa applicazione sono quasi tutte "di sola lettura" e arriva abbastanza rapidamente (anche se i dati richiesti sono piuttosto piccoli).

È stato utile?

Soluzione

In realtà non sono d'accordo con l'utilizzo di Commons DBCP. Dovresti davvero rimandare al contenitore per gestire il pool di connessioni per te.

Dato che stai usando Java Servlet, ciò implica l'esecuzione in un container Servlet, e tutti i principali container Servlet con cui ho familiarità forniscono la gestione del pool di connessioni (le specifiche Java EE potrebbero addirittura richiederlo). Se il tuo contenitore utilizza DBCP (come fa Tomcat), ottimo, altrimenti, usa qualunque cosa il tuo contenitore fornisca.

Altri suggerimenti

Come dicono tutti, è necessario utilizzare un pool di connessioni. Perché? Cosa succede? Ecc.

Cosa c'è che non va nella tua soluzione

Lo so da quando ho anche pensato che fosse una buona idea una volta. Il problema è duplice:

  1. Tutti i thread (le richieste servlet vengono soddisfatte con un thread per ciascuno) condivideranno la stessa connessione. Le richieste verranno quindi elaborate una alla volta. Questo è molto lento, anche se ti siedi in un unico browser e ti appoggi al tasto F5. Provalo: questa roba suona di alto livello e astratta, ma è empirica e testabile.
  2. Se la connessione si interrompe per qualsiasi motivo, il metodo init non verrà richiamato nuovamente (poiché il servlet non verrà messo fuori servizio). Non provare a gestire questo problema inserendo un try-catch in doGet o doPost, perché in questo modo sarai all'inferno (scrivendo un app server senza che ti venga chiesto).
  3. Contrariamente a quanto si potrebbe pensare, non si avranno problemi con le transazioni, poiché l'inizio della transazione viene associato al thread e non solo alla connessione. Potrei sbagliarmi, ma dal momento che questa è una cattiva soluzione, non sudare.

Perché il pool di connessioni

I pool di connessione offrono numerosi vantaggi, ma soprattutto risolvono i problemi di

  1. Realizzare una vera connessione al database è costoso. Il pool di connessioni ha sempre alcune connessioni extra in giro e ti dà una di quelle.
  2. Se le connessioni falliscono, il pool di connessioni sa come aprirne uno nuovo
  3. Molto importante: ogni thread ha la propria connessione. Ciò significa che il threading viene gestito dove dovrebbe essere: a livello di DB. I DB sono super efficienti e possono gestire facilmente richieste simultanee.
  4. Altre cose (come centralizzare la posizione delle stringhe di connessione JDBC, ecc.), ma ci sono milioni di articoli, libri, ecc. su questo

Quando ottenere una connessione

Da qualche parte nello stack di chiamate avviato nel delegato del servizio (doPost, doGet, doDisco, qualunque cosa) dovresti ottenere una connessione e quindi dovresti fare la cosa giusta e restituirla in un blocco finalmente. Vorrei ricordare che il tizio dell'architetto principale di C # ha detto una volta ogni volta che dovresti usare i blocchi infine 100 volte più dei blocchi catch . Parole più vere mai pronunciate ...

Quale pool di connessioni

Sei in un servlet, quindi dovresti usare il pool di connessioni fornito dal contenitore. Il tuo codice JNDI sarà completamente normale, tranne per come ottenere la connessione. Per quanto ne so, tutti i contenitori servlet dispongono di pool di connessioni.

Alcuni dei commenti sulle risposte sopra suggeriscono invece di utilizzare una particolare API del pool di connessioni. La tua WAR dovrebbe essere portatile e " basta implementare " Penso che sia fondamentalmente sbagliato. Se si utilizza il pool di connessioni fornito dal proprio contenitore, l'app sarà distribuibile su contenitori che si estendono su più macchine e su tutte le cose fantasiose fornite dalle specifiche Java EE. Sì, i descrittori di distribuzione specifici del contenitore dovranno essere scritti, ma questo è il modo EE, mon.

Un commentatore menziona che alcuni pool di connessioni forniti dal contenitore non funzionano con i driver JDBC (menziona Websphere). Sembra totalmente inverosimile e ridicolo, quindi probabilmente è vero. Quando succedono cose del genere, lancia tutto quello che dovresti fare " nella spazzatura e fai tutto il possibile. Questo è ciò per cui siamo pagati, a volte :)

Vorrei utilizzare Commons DBCP . È un progetto Apache che gestisce il pool di connessioni per te.

Avresti semplicemente ottenuto la tua connessione nel tuo doGet o doPost eseguendo la tua query e chiudendo la connessione in un blocco finally. (con.close () lo restituisce al pool, in realtà non lo chiude).

DBCP può gestire i timeout della connessione e ripristinarli. Nel modo in cui stai facendo le cose se il database si interrompe per un periodo di tempo, dovrai riavviare l'applicazione.

Stai unendo le tue connessioni? In caso contrario, probabilmente dovresti ridurre il sovraccarico di apertura e chiusura delle connessioni.

Una volta che è fuori mano, mantieni la connessione aperta per tutto il tempo necessario, come ha suggerito John.

Il modo migliore, e attualmente sto cercando su Google un foglio di riferimento migliore, è utilizzare i pool.

All'inizializzazione, si crea un pool che contiene il numero X di oggetti di connessione SQL al database. Archivia questi oggetti in una sorta di Elenco, come ArrayList. Ognuno di questi oggetti ha un valore booleano privato per "isLeased", molto tempo per l'ultima volta in cui è stato utilizzato e una connessione. Ogni volta che hai bisogno di una connessione, ne richiedi una dal pool. Il pool ti darà la prima connessione disponibile, controllando la variabile isLeased, oppure ne creerà una nuova e la aggiungerà al pool. Assicurati di impostare il timestamp. Una volta terminata la connessione, è sufficiente restituirla al pool, che imposterà isLeased su false.

Per evitare che le connessioni si leghino costantemente al database, è possibile creare un thread di lavoro che occasionalmente passerà attraverso il pool e vedrà quando è stata utilizzata l'ultima connessione. Se è stato abbastanza a lungo, può chiudere quella connessione e rimuoverla dal pool.

I vantaggi dell'utilizzo di questo è che non si hanno lunghi tempi di attesa in attesa che un oggetto Connection si connetta al database. Le tue connessioni già stabilite possono essere riutilizzate quanto vuoi. E sarai in grado di impostare il numero di connessioni in base a quanto pensi che sarà la tua applicazione.

Dovresti tenere aperta una connessione al database per tutto il tempo necessario, il che dipende da ciò che stai facendo è probabilmente nell'ambito dei tuoi metodi doGet / doPost .

Pool it.

Inoltre, se stai eseguendo JDBC non elaborato, potresti cercare qualcosa che ti aiuti a gestire la connessione, lo stato preparato, ecc. A meno che tu non abbia una "leggerezza" molto stretta "; i requisiti, ad esempio utilizzando il supporto JDBC di Spring, semplificheranno molto il tuo codice e non sei obbligato a utilizzare qualsiasi altra parte di Spring.

Vedi alcuni esempi qui:

http://static.springframework.org/spring /docs/2.5.x/reference/jdbc.html

Un pool di connessioni associato a un'origine dati dovrebbe fare il trucco. Puoi ottenere la connessione da dataSource nel metodo di richiesta servlet ( doget / dopost , ecc.)

dbcp, c3p0 e molti altri pool di connessioni possono fare quello che stai cercando. Durante il pooling delle connessioni, è possibile che si desideri unire le istruzioni e PreparedStatements; Inoltre, se sei un ambiente READ HEAVY come indicato, potresti voler memorizzare alcuni dei risultati nella cache usando qualcosa come ehcache.

BR,
~ A

Di solito scoprirai che l'apertura delle connessioni per richiesta è più facile da gestire. Ciò significa che nel metodo doPost () o doGet () del servlet.

Aprendolo in init () lo rende disponibile per tutte le richieste e cosa succede quando si hanno richieste simultanee?

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top