Chiusura delle connessioni JDBC nel pool


109

La nostra sezione di codice standard per l'utilizzo di JDBC è ...

Connection conn = getConnection(...);
Statement  stmt = conn.conn.createStatement (ResultSet.TYPE_SCROLL_INSENSITIVE,
                                                ResultSet.CONCUR_READ_ONLY);
ResultSet  rset = stmt.executeQuery (sqlQuery);

// do stuff with rset

rset.close(); stmt.close(); conn.close();

Domanda 1: quando si utilizza Connection Pool, è necessario chiudere la connessione alla fine? Se è così, lo scopo del pooling non è perso? E se no, come fa DataSource a sapere quando una particolare istanza di Connection viene liberata e può essere riutilizzata? Sono un po 'confuso su questo, eventuali suggerimenti sono stati apprezzati.

Domanda 2: il seguente metodo è vicino allo standard? Sembra un tentativo di ottenere una connessione dal pool e, se non è possibile stabilire DataSource, utilizzare il vecchio DriverManager. Non siamo nemmeno sicuri di quale parte venga eseguita in fase di esecuzione. Ripetendo la domanda precedente, si dovrebbe chiudere la connessione che esce da un tale metodo?

Grazie, - MS.

synchronized public Connection getConnection (boolean pooledConnection)
                                                        throws SQLException {
        if (pooledConnection) {
                if (ds == null) {
                        try {
                                Context envCtx = (Context)
                                        new InitialContext().lookup("java:comp/env");
                                ds = (DataSource) envCtx.lookup("jdbc/NamedInTomcat");
                                return ds.getConnection();
                        } catch (NamingException e) {
                                e.printStackTrace();
                }}
                return (ds == null) ? getConnection (false) : ds.getConnection();
        }
        return DriverManager.getConnection(
                "jdbc:mysql://"+ipaddy+":"+dbPort +"/" + dbName, uName, pWord);
}

Modifica: penso che stiamo ottenendo la connessione in pool poiché non vediamo una traccia dello stack.

Risposte:


121

Quando si utilizza Connection Pool, si dovrebbe chiudere la connessione alla fine? Se è così, lo scopo del pooling non è perso? E se no, come fa DataSource a sapere quando una particolare istanza di Connection viene liberata e può essere riutilizzata? Sono un po 'confuso su questo, eventuali suggerimenti sono stati apprezzati.

Sì, certamente è necessario chiudere anche la connessione in pool. In realtà è un involucro attorno alla connessione effettiva. Sotto le coperte verrà rilasciata la connessione effettiva alla piscina. Sta al pool decidere se la connessione effettiva verrà effettivamente chiusa o riutilizzata per una nuova getConnection()chiamata. Quindi, indipendentemente dal fatto che tu stia utilizzando o meno un pool di connessioni, dovresti sempre chiudere tutte le risorse JDBC in ordine inverso nel finallyblocco del tryblocco in cui le hai acquisite. In Java 7 questo può essere ulteriormente semplificato utilizzando l' try-with-resourcesistruzione.


Il metodo seguente è vicino allo standard? Sembra un tentativo di ottenere una connessione dal pool e, se non è possibile stabilire DataSource, utilizzare il vecchio DriverManager. Non siamo nemmeno sicuri di quale parte venga eseguita in fase di esecuzione. Ripetendo la domanda precedente, si dovrebbe chiudere la connessione che esce da un tale metodo?

L'esempio è piuttosto spaventoso. Hai solo bisogno di cercare / inizializzare l' DataSourceunica volta durante l'avvio dell'applicazione in un costruttore / inizializzazione di una classe di configurazione DB a livello di applicazione. Quindi basta chiamare getConnection()la stessa origine dati per il resto della vita dell'applicazione. Non c'è bisogno di sincronizzazione né di nullcheck.

Guarda anche:


Questo è quello che sta facendo (inizializza una volta), non è vero? ds è una variabile di istanza e if (ds == null) ... è la parte di inizializzazione.
Manidip Sengupta

Fare i controlli ogni volta con un metodo get getConnection()è strano. Basta farlo in c'tor o blocco di inizializzazione della stessa classe, senza sincronizzazione / nullchecks. Sarà chiamato solo una volta. Per ulteriori suggerimenti ed esempi di kickoff, potresti trovare utile questo articolo .
BalusC

Ottimo articolo, BalusC. La classe con cui ho a che fare implementa praticamente il livello dati, utilizzando DTO. Sono d'accordo con te, l'inizializzazione dovrebbe essere nel costruttore. Ora, questa classe ha un sacco di metodi, ciascuno con conn, stmt e rset come variabili locali, le connessioni sono in un blocco try e infine c'è una chiamata a 1 riga csrClose (conn, stmt, rset), dove tutte e 3 sono chiusi (in ordine inverso). Ora, il DTO sviluppato nell'esempio è un'immagine speculare di una riga della tabella DB. Abbiamo query SQL complesse con join (e altre clausole), hai un articolo su come sviluppare DAO per tali risultati?
Manidip Sengupta

2
@yat: DEVI richiamarli close()tutti nel finallyblocco dello stesso tryblocco in cui li hai acquisiti / creati. Questo è completamente indipendentemente dal fatto che si tratti di una connessione in pool o meno.
BalusC

1
@iJava: quella piscina è scritta da un dilettante che non ha la più pallida idea di cosa stia facendo. Ignoralo e scegli una vera libreria. Ad esempio HikariCP.
BalusC

22

I pool in genere restituiscono un oggetto Connection avvolto, in cui il metodo close () viene sovrascritto, tipicamente restituendo la connessione al pool. Chiamare close () è OK e probabilmente è ancora necessario.

Un metodo close () sarebbe probabilmente simile a questo:

public void close() throws SQLException {
  pool.returnConnection(this);
}

Per la tua seconda domanda, potresti aggiungere un logger per mostrare se il blocco inferiore viene mai eseguito. Immagino che tu voglia solo in un modo o nell'altro per la configurazione delle connessioni al database. Usiamo esclusivamente un pool per i nostri accessi al database. In ogni caso, chiudere la connessione sarebbe piuttosto importante per evitare perdite.


Sono d'accordo, abbiamo un logger e potrebbe essere usato anche qui. Ho bisogno di studiare un po 'come puoi avvolgere un oggetto, sovrascrivere il suo metodo close () ma mantenere lo stesso nome di classe (connessione)
Manidip Sengupta

1
Calling close() is OK and probably still required., se non si chiama close perderà la connessione, a meno che il pool non implementa una strategia di ripristino
svarog

0

In realtà, l'approccio migliore alla gestione delle connessioni è non distribuirli a nessun codice da nessuna parte.

Creare una classe SQLExecutor che sia l'unica posizione che apre e chiude le connessioni.

L'intero resto dell'applicazione quindi pompa le istruzioni nell'esecutore piuttosto che ottenere connessioni dal pool e gestirle (o gestirle in modo errato) dappertutto.

Puoi avere tutte le istanze dell'esecutore che desideri, ma nessuno dovrebbe scrivere codice che apra e chiuda le connessioni per proprio conto.

Convenientemente, questo ti consente anche di registrare tutto il tuo SQL da un singolo set di codice.

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.