Schließen von JDBC-Verbindungen im Pool

109

Unser Standardcode-Abschnitt für die Verwendung von JDBC ist ...

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();

Frage 1: Sollte man bei Verwendung des Verbindungspools die Verbindung am Ende schließen? Wenn ja, ist der Zweck des Pooling nicht verloren? Und wenn nicht, woher weiß die DataSource, wann eine bestimmte Instanz von Connection freigegeben wurde und wiederverwendet werden kann? Ich bin ein wenig verwirrt, alle Hinweise sind willkommen.

Frage 2: Entspricht die folgende Methode dem Standard? Sieht aus wie ein Versuch, eine Verbindung aus dem Pool herzustellen. Wenn DataSource nicht hergestellt werden kann, verwenden Sie den altmodischen DriverManager. Wir sind uns nicht einmal sicher, welcher Teil zur Laufzeit ausgeführt wird. Wenn man die obige Frage wiederholt, sollte man die Verbindung schließen, die aus einer solchen Methode hervorgeht?

Vielen Dank, - 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);
}

Bearbeiten: Ich denke, wir bekommen die gepoolte Verbindung, da wir keinen Stack-Trace sehen.

Manidip Sengupta
quelle

Antworten:

121

Sollte man bei Verwendung des Verbindungspools die Verbindung am Ende schließen? Wenn ja, ist der Zweck des Pooling nicht verloren? Und wenn nicht, woher weiß die DataSource, wann eine bestimmte Instanz von Connection freigegeben wurde und wiederverwendet werden kann? Ich bin ein wenig verwirrt, alle Hinweise sind willkommen.

Ja, natürlich müssen Sie auch die Poolverbindung schließen. Es ist eigentlich ein Wrapper um die eigentliche Verbindung. Es wird unter der Decke die eigentliche Verbindung zum Pool freigeben. Es liegt weiter am Pool zu entscheiden, ob die tatsächliche Verbindung tatsächlich geschlossen oder für einen neuen getConnection()Anruf wiederverwendet wird . Also, unabhängig davon , ob Sie einen Verbindungspool verwenden oder nicht, sollten Sie immer schließen alle JDBC - Ressourcen in umgekehrter Reihenfolge in dem finallyBlock des tryBlocks , in dem Sie sie erworben haben. In Java 7 kann dies mithilfe der try-with-resourcesAnweisung weiter vereinfacht werden .


Entspricht die folgende Methode dem Standard? Sieht aus wie ein Versuch, eine Verbindung aus dem Pool herzustellen. Wenn DataSource nicht hergestellt werden kann, verwenden Sie den altmodischen DriverManager. Wir sind uns nicht einmal sicher, welcher Teil zur Laufzeit ausgeführt wird. Wenn man die obige Frage wiederholt, sollte man die Verbindung schließen, die aus einer solchen Methode hervorgeht?

Das Beispiel ist ziemlich beängstigend. Sie müssen DataSourcenur einmal während des Starts der Anwendung in einem Konstruktor / einer Initialisierung einer anwendungsweiten DB-Konfigurationsklasse nachschlagen / initialisieren. getConnection()Rufen Sie dann während der restlichen Lebensdauer der Anwendung einfach dieselbe Datenquelle auf. Keine Notwendigkeit für Synchronisation oder Nullchecks.

Siehe auch:

BalusC
quelle
Das ist es, was es tut (einmal initialisieren), nicht wahr? ds ist eine Instanzvariable, und if (ds == null) ... ist der Initialisierungsteil.
Manidip Sengupta
Es ist seltsam, die Überprüfungen jedes Mal in einer get-Methode wie durchzuführengetConnection() . Tun Sie es einfach in c'tor oder Initialisierungsblock derselben Klasse, ohne Synchronisation / Nullchecks. Es wird nur einmal aufgerufen. Weitere Hinweise und Kickoff-Beispiele finden Sie in diesem Artikel .
BalusC
Ausgezeichneter Artikel, BalusC. Die Klasse, mit der ich es zu tun habe, implementiert die Datenschicht mithilfe von DTOs. Ich stimme Ihnen zu, die Initialisierung sollte im Konstruktor erfolgen. Jetzt hat diese Klasse eine Menge Methoden, jede mit conn, stmt und rset als lokalen Variablen, Verbindungen befinden sich in einem try-Block, und schließlich gibt es einen 1-zeiligen Aufruf csrClose (conn, stmt, rset), wobei alle 3 sind geschlossen (in umgekehrter Reihenfolge). Das DTO, das Sie im Beispiel entwickeln, ist ein Spiegelbild einer DB-Tabellenzeile. Wir haben komplexe SQL-Abfragen mit Joins (und anderen Klauseln). Haben Sie einen Artikel darüber, wie Sie DAOs für solche Ergebnisse entwickeln können?
Manidip Sengupta
2
@yat: Sie MÜSSEN close()alle im finallyBlock desselben tryBlocks aufrufen , in dem Sie sie erworben / erstellt haben. Dies ist völlig unabhängig davon, ob es sich um eine Poolverbindung handelt oder nicht.
BalusC
1
@iJava: Dieser Pool wurde von einem Amateur geschrieben, der keine Ahnung hat, was er tut. Ignoriere es und such dir eine echte Bibliothek. ZB HikariCP.
BalusC
22

Die Pools geben normalerweise ein umschlossenes Verbindungsobjekt zurück, bei dem die Methode close () überschrieben wird, und geben normalerweise die Verbindung an den Pool zurück. Das Aufrufen von close () ist in Ordnung und wahrscheinlich noch erforderlich.

Eine close () -Methode würde wahrscheinlich so aussehen:

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

Für Ihre zweite Frage können Sie einen Logger hinzufügen, um anzuzeigen, ob der untere Block jemals ausgeführt wird. Ich würde mir vorstellen, dass Sie nur die eine oder andere Art der Konfiguration Ihrer Datenbankverbindungen wünschen. Wir verwenden ausschließlich einen Pool für unsere Datenbankzugriffe. In jedem Fall wäre das Schließen der Verbindung ziemlich wichtig, um Undichtigkeiten zu vermeiden.

taer
quelle
Ich stimme zu, wir haben einen Logger, und der könnte auch hier verwendet werden. Ich muss ein wenig darüber lernen, wie Sie ein Objekt
umschließen
1
Calling close() is OK and probably still required.
Wenn Sie
0

Tatsächlich besteht der beste Ansatz für das Verbindungsmanagement darin, sie nirgendwo in Code umzuwandeln.

Erstellen Sie eine SQLExecutor-Klasse, die der einzige Speicherort ist, an dem Verbindungen geöffnet und geschlossen werden.

Der gesamte Rest der Anwendung pumpt dann Anweisungen in den Executor, anstatt Verbindungen aus dem Pool abzurufen und sie überall zu verwalten (oder zu verwalten).

Sie können so viele Instanzen des Executors haben, wie Sie möchten, aber niemand sollte Code schreiben, der Verbindungen in eigenem Namen öffnet und schließt.

Auf diese Weise können Sie auch Ihr gesamtes SQL aus einem einzigen Codesatz protokollieren.

Rodney P. Barbati
quelle