web-dev-qa-db-ja.com

接続は後で閉じられますが、JDBC結果セットとステートメントは別々に閉じる必要がありますか?

使用後にすべてのJDBCリソースを閉じるのは良い習慣だと言われています。しかし、次のようなコードがある場合は、ResultsetとStatementを閉じる必要がありますか?

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) {};
}

問題は、接続を閉じてもうまくいくのか、それとも一部のリソースが使用中になってしまうのかということです。

229
Zeemee

あなたがしたことは完璧でとても良い習慣です。

たとえば、何らかの理由で「プリミティブ」タイプのデータベースプーリングを使用していてconnection.close()を呼び出すと、接続はプールに返され、ResultSet/Statementは閉じられません。そして、あなたは多くの異なる新しい問題に出くわすでしょう!

ですから、あなたはいつもconnection.close()を片付けてくれるわけではありません。

これが役に立つことを願っています:)

180
Paul

Java 1.7は try-with-resourcesステートメント のおかげで私たちの生活をはるかに楽にします。

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.
    }
}

この構文は非常に簡潔でエレガントです。 connectionが作成できなかった場合でも、statementは実際に閉じられます。

javadocs から:

Statementオブジェクトが閉じられると、その現在のResultSetオブジェクトが存在する場合はそれも閉じられます。

ただし、基礎となるStatementを閉じるときにResultSetConnectionが閉じられるかどうかについては、javadocはあまり明確ではありません。彼らは単にコネクションを閉じることを述べている:

自動的に解放されるのを待つのではなく、このConnectionオブジェクトのデータベースとJDBCリソースを直ちに解放します。

ResultSetsの実装はデータベースドライバによって異なる可能性があるため、これらを使い終わったら、StatementsConnections、およびcloseを常に明示的に閉じるようにしてください。

Apacheの DBUtils の中のcloseQuietlyのようなメソッドを使うことで、たくさんの定型コードを節約することができます。

65
dogbane

現在、OracleをJavaで使用しています。ここで私の視点:

Oracleは以前に接続を閉じた後でもカーソルを開いたままにしておくことに問題があるため、ResultSetおよびStatementを明示的に閉じる必要があります。 ResultSet(カーソル)を閉じないと、Maximum open cursors exceededのようなエラーがスローされます。

使用している他のデータベースでも同じ問題が発生する可能性があると思います。

チュートリアル 終了したらResultSetを閉じる

終了したらResultSetを閉じる

ResultSetオブジェクトは、ResultSetオブジェクトが閉じたときに暗黙的にStatementオブジェクトを閉じますが、ResultSetオブジェクトを閉じるとすぐにResultSetオブジェクトを閉じます。 ResultSetオブジェクトはクエリに応じて多くのメモリを占有する可能性があるため、メモリをできるだけ早く再収集するためにガベージコレクタへ。

ResultSet.close();

35
user467871

よりコンパクトなコードが必要な場合は、 Apache Commons DbUtils を使用することをお勧めします。この場合:

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

JDBCに関連付けられているリソースを閉じるための適切で安全な方法は、次のとおりです( JDBCリソースを正しく閉じる方法 - 毎回 ):

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

Connectionがプール可能かどうかは関係ありません。プールに戻る前にプール可能な接続でもクリーンアップする必要があります。

「クリーン」とは通常、結果セットを閉じて保留中のトランザクションをロールバックすることを意味しますが、接続を閉じないことを意味します。それ以外の場合、プールすると意味がなくなります。

2
Mad Calm

いくつかの便利な機能:

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

いいえ、接続を閉じる必要はありません。 JDBC仕様ごとに上位オブジェクトを閉じると、下位オブジェクトも自動的に閉じます。 Connectionを閉じると、接続によって作成されたStatementが閉じられます。 Statementを閉じると、そのResultSetによって作成されたすべてのStatementが閉じます。 Connectionがプール可能かどうかは関係ありません。プールに戻る前にプール可能な接続でもクリーンアップする必要があります。

もちろんConnection上で長いネストしたループがたくさんのステートメントを作成しているかもしれません、そしてそれらを閉じることは適切です。私はResultSetを閉じることはほとんどありませんが、Statementを閉じるとき、またはConnectionを閉じるときには過剰に見えます。

0
Enerccio