web-dev-qa-db-de.com

Müssen JDBC-Resultsets und -Anweisungen separat geschlossen werden, obwohl die Verbindung danach geschlossen wird?

Es ist eine gute Angewohnheit, alle JDBC-Ressourcen nach der Verwendung zu schließen. Muss ich die Ergebnismenge und die Anweisung schließen, wenn ich den folgenden Code habe?

Connection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
try {
    conn = // Retrieve connection
    stmt = conn.prepareStatement(// Some SQL);
    rs = stmt.executeQuery();
} catch(Exception e) {
    // Error Handling
} finally {
    try { if (rs != null) rs.close(); } catch (Exception e) {};
    try { if (stmt != null) stmt.close(); } catch (Exception e) {};
    try { if (conn != null) conn.close(); } catch (Exception e) {};
}

Die Frage ist, ob das Schließen der Verbindung den Job erledigt oder ob einige Ressourcen belegt sind.

233
Zeemee

Was Sie getan haben, ist perfekt und sehr gute Praxis.

Der Grund, warum ich es für eine gute Praxis halte ... Wenn Sie beispielsweise aus irgendeinem Grund einen "primitiven" Typ von Datenbankpooling verwenden und connection.close() aufrufen, wird die Verbindung an den Pool zurückgegeben und der ResultSet/Statement wird niemals geschlossen, und dann treten viele neue Probleme auf!

Sie können sich also nicht immer darauf verlassen, dass connection.close() aufräumt.

Ich hoffe das hilft :)

185
Paul

Java 1.7 erleichtert uns das Leben dank der try-with-resources-Anweisung .

try (Connection connection = dataSource.getConnection();
    Statement statement = connection.createStatement()) {
    try (ResultSet resultSet = statement.executeQuery("some query")) {
        // Do stuff with the result set.
    }
    try (ResultSet resultSet = statement.executeQuery("some query")) {
        // Do more stuff with the second result set.
    }
}

Diese Syntax ist recht kurz und elegant. Und connection wird in der Tat geschlossen, auch wenn das statement nicht erstellt werden konnte.

Aus dem javadocs :

Wenn ein Statement -Objekt geschlossen wird, wird auch sein aktuelles ResultSet -Objekt geschlossen, sofern eines vorhanden ist.

Die Javadocs wissen jedoch nicht genau, ob Statement und ResultSet geschlossen sind, wenn Sie das zugrunde liegende Connection schließen. Sie geben einfach an, dass eine Verbindung geschlossen wird:

Gibt die Datenbank und die JDBC-Ressourcen dieses Connection Objekts sofort frei, anstatt darauf zu warten, dass sie automatisch freigegeben werden.

Nach meiner Meinung sollten Sie ResultSets, Statements und Connections immer explizit schließen, wenn Sie damit fertig sind, da die Implementierung von close zwischen den Datenbanktreibern variieren kann.

Sie können sich mit Methoden wie closeQuietly in DBUtils von Apache eine Menge Code sparen.

67
dogbane

Ich benutze jetzt Oracle mit Java. Hier meine Sichtweise:

Sie sollten ResultSet und Statement explizit schließen, da Oracle zuvor Probleme damit hatte, die Cursor auch nach dem Schließen der Verbindung offen zu halten. Wenn Sie den ResultSet (Cursor) nicht schließen, wird ein Fehler wie ausgelöst. Die maximale Anzahl offener Cursor wurde überschritten .

Ich denke, Sie könnten das gleiche Problem mit anderen von Ihnen verwendeten Datenbanken haben.

Hier ist das Tutorial Schließen Sie ResultSet, wenn Sie fertig sind :

Schließen Sie ResultSet, wenn Sie fertig sind

Schließen Sie das Objekt ResultSet, sobald Sie mit dem Objekt ResultSet fertig sind, obwohl das Objekt Statement das Objekt ResultSet beim Schließen implizit schließt, und schließen Sie ResultSet gibt explizit die Möglichkeit, den Garbage Collector so früh wie möglich zum Speichern zu bewegen, da das Objekt ResultSet je nach Abfrage möglicherweise viel Speicher belegt.

ResultSet.close();

35
user467871

Wenn Sie kompakter Code möchten, empfehle ich die Verwendung von Apache Commons DbUtils . In diesem Fall:

Connection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
try {
    conn = // Retrieve connection
    stmt = conn.prepareStatement(// Some SQL);
    rs = stmt.executeQuery();
} catch(Exception e) {
    // Error Handling
} finally {
    DbUtils.closeQuietly(rs);
    DbUtils.closeQuietly(stmt);
    DbUtils.closeQuietly(conn);
}
6
baron5

Es spielt keine Rolle, ob Connection poolfähig ist oder nicht. Auch poolfähige Verbindungen müssen vor der Rückkehr in den Pool gereinigt werden.

"Bereinigen" bedeutet normalerweise, Ergebnismengen zu schließen und alle ausstehenden Transaktionen zurückzusetzen, aber die Verbindung nicht zu schließen, da andernfalls das Pooling den Sinn verliert.

3
Mad Calm

Die korrekte und sichere Methode zum Schließen der mit JDBC verknüpften Ressourcen ist diese (entnommen aus So schließen Sie JDBC-Ressourcen ordnungsgemäß - jedes Mal ):

Connection connection = dataSource.getConnection();
try {
    Statement statement = connection.createStatement();

    try {
        ResultSet resultSet = statement.executeQuery("some query");

        try {
            // Do stuff with the result set.
        } finally {
            resultSet.close();
        }
    } finally {
        statement.close();
    }
} finally {
    connection.close();
}

Einige Komfortfunktionen:

public static void silentCloseResultSets(Statement st) {
    try {
        while (!(!st.getMoreResults() && (st.getUpdateCount() == -1))) {}
    } catch (SQLException ignore) {}
}
public static void silentCloseResultSets(Statement ...statements) {
    for (Statement st: statements) silentCloseResultSets(st);
}
0
Mad Calm

Nein, Sie müssen nichts schließen, ABER die Verbindung. Gemäß den JDBC-Spezifikationen werden niedrigere Objekte automatisch geschlossen, wenn ein höheres Objekt geschlossen wird. Wenn Sie Connection schließen, werden alle Statements geschlossen, die von dieser Verbindung erstellt wurden. Wenn Sie ein Statement schließen, werden alle ResultSets geschlossen, die von diesem Statement erstellt wurden. Es spielt keine Rolle, ob Connection poolfähig ist oder nicht. Auch poolfähige Verbindungen müssen vor der Rückkehr in den Pool gereinigt werden.

Natürlich könnten Sie lange verschachtelte Schleifen auf dem Connection haben, die viele Anweisungen erzeugen, dann ist es angebracht, sie zu schließen. Ich schließe ResultSet so gut wie nie, scheint aber übermäßig zu sein, wenn ich Statement oder Connection schließe.

0
Enerccio