使用後にすべての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) {};
}
問題は、接続を閉じてもうまくいくのか、それとも一部のリソースが使用中になってしまうのかということです。
あなたがしたことは完璧でとても良い習慣です。
たとえば、何らかの理由で「プリミティブ」タイプのデータベースプーリングを使用していてconnection.close()
を呼び出すと、接続はプールに返され、ResultSet
/Statement
は閉じられません。そして、あなたは多くの異なる新しい問題に出くわすでしょう!
ですから、あなたはいつもconnection.close()
を片付けてくれるわけではありません。
これが役に立つことを願っています:)
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
を閉じるときにResultSet
とConnection
が閉じられるかどうかについては、javadocはあまり明確ではありません。彼らは単にコネクションを閉じることを述べている:
自動的に解放されるのを待つのではなく、この
Connection
オブジェクトのデータベースとJDBCリソースを直ちに解放します。
ResultSets
の実装はデータベースドライバによって異なる可能性があるため、これらを使い終わったら、Statements
、Connections
、およびclose
を常に明示的に閉じるようにしてください。
Apacheの DBUtils の中のcloseQuietly
のようなメソッドを使うことで、たくさんの定型コードを節約することができます。
現在、OracleをJavaで使用しています。ここで私の視点:
Oracleは以前に接続を閉じた後でもカーソルを開いたままにしておくことに問題があるため、ResultSet
およびStatement
を明示的に閉じる必要があります。 ResultSet
(カーソル)を閉じないと、Maximum open cursors exceededのようなエラーがスローされます。
使用している他のデータベースでも同じ問題が発生する可能性があると思います。
チュートリアル 終了したらResultSetを閉じる :
終了したらResultSetを閉じる
ResultSet
オブジェクトは、ResultSet
オブジェクトが閉じたときに暗黙的にStatement
オブジェクトを閉じますが、ResultSet
オブジェクトを閉じるとすぐにResultSet
オブジェクトを閉じます。ResultSet
オブジェクトはクエリに応じて多くのメモリを占有する可能性があるため、メモリをできるだけ早く再収集するためにガベージコレクタへ。
ResultSet.close();
よりコンパクトなコードが必要な場合は、 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);
}
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
がプール可能かどうかは関係ありません。プールに戻る前にプール可能な接続でもクリーンアップする必要があります。
「クリーン」とは通常、結果セットを閉じて保留中のトランザクションをロールバックすることを意味しますが、接続を閉じないことを意味します。それ以外の場合、プールすると意味がなくなります。
いくつかの便利な機能:
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);
}
いいえ、接続を閉じる必要はありません。 JDBC仕様ごとに上位オブジェクトを閉じると、下位オブジェクトも自動的に閉じます。 Connection
を閉じると、接続によって作成されたStatement
が閉じられます。 Statement
を閉じると、そのResultSet
によって作成されたすべてのStatement
が閉じます。 Connection
がプール可能かどうかは関係ありません。プールに戻る前にプール可能な接続でもクリーンアップする必要があります。
もちろんConnection
上で長いネストしたループがたくさんのステートメントを作成しているかもしれません、そしてそれらを閉じることは適切です。私はResultSet
を閉じることはほとんどありませんが、Statement
を閉じるとき、またはConnection
を閉じるときには過剰に見えます。