Javaでデータベース接続を閉じる


121

私は少し混乱しています、以下をhttp://en.wikipedia.org/wiki/Java_Database_Connectivityから読んでいました

Connection conn = DriverManager.getConnection(
     "jdbc:somejdbcvendor:other data needed by some jdbc vendor",
     "myLogin",
     "myPassword" );

Statement stmt = conn.createStatement();
try {
    stmt.executeUpdate( "INSERT INTO MyTable( name ) VALUES ( 'my name' ) " );
} finally {
    //It's important to close the statement when you are done with it
    stmt.close();
}

conn接続を閉じる必要はありませんか?conn.close()が発生しない場合、実際には何が起こっていますか?

私が管理しているプラ​​イベートWebアプリがありますが、現在どちらのフォームも閉じていませんが、重要なものは本当にstmt、conn、またはその両方ですか?

サイトは断続的にダウンし続けますが、サーバーはデータベース接続の問題だと言い続けます。私の疑いは閉じられていませんが、どちらを閉じるかわかりません。


クローズを処理する他のドライバーやテンプレートに依存することなく、常に自分で接続をクローズすることがベストプラクティスです。接続のクローズに失敗すると、クラッシュ(リソースシナリオがなくなる)または再起動するまで、ソケットとリソースが永久に開かれます。
アルンジョシュラ

回答:


196

の使用が終了したらConnectionclose()接続が保持している可能性のある他のデータベースリソース(カーソル、ハンドルなど)を解放するために、そのメソッドを呼び出して明示的に閉じる必要があります。

実際には、Javaで安全なパターンは、あなたの閉じることでResultSetStatementConnectionに(そのために)finallyあなたは彼らと一緒に行われたときに、ブロックのようなものを:

Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;

try {
    // Do stuff
    ...

} catch (SQLException ex) {
    // Exception handling stuff
    ...
} finally {
    if (rs != null) {
        try {
            rs.close();
        } catch (SQLException e) { /* ignored */}
    }
    if (ps != null) {
        try {
            ps.close();
        } catch (SQLException e) { /* ignored */}
    }
    if (conn != null) {
        try {
            conn.close();
        } catch (SQLException e) { /* ignored */}
    }
}

finallyブロックは、わずかに(ヌルチェックを回避するため)に向上させることができます。

} finally {
    try { rs.close(); } catch (Exception e) { /* ignored */ }
    try { ps.close(); } catch (Exception e) { /* ignored */ }
    try { conn.close(); } catch (Exception e) { /* ignored */ }
}

しかし、それでも、これは非常に冗長であるため、通常はヘルパークラスを使用してnullセーフヘルパーメソッドでオブジェクトを閉じ、finallyブロックは次のようになります。

} finally {
    DbUtils.closeQuietly(rs);
    DbUtils.closeQuietly(ps);
    DbUtils.closeQuietly(conn);
}

そして、実際には、Apache Commons DbUtilsには、DbUtilsそれを正確に実行するクラスがあるため、独自のクラスを作成する必要はありません。


3
素晴らしいヘルプ、ありがとう!私はconn!= nullステートメントをキャッチまたは考えませんでした。
onaclov2000

1
@ onaclov2000はい、rspsconnすることができるnull場所コードブレークに応じました。これが「安全な」パターンとして知られている理由です。
Pascal Thivent、2010

12
@Pascal Thivent:実際には、すべてを閉じる必要はありません。「コアJavaボリューム2-高度な機能」の本は次のように書いています:オブジェクトのcloseメソッドは、ステートメントに開いている結果セットがある場合、Statement関連するオブジェクトを自動的に閉じますResultSet。同様closeに、Connectionクラスのメソッドは、すべてのStatementsを閉じますConnection
Majid Azimi

12
@Majid:プールされた接続でない限り。その後、ステートメントは漏洩します。
BalusC 2013年

1
@BalusC:プールされた接続がconnection.close()メソッドを使用して閉じられたときに何が起こるか説明できますか
Krsna Chaitanya

61

使用後は常にデータベース/リソースオブジェクトを閉じることをお勧めします。finallyブロック内の接続、結果セット、ステートメントオブジェクトを閉じる方が適切です。

Java7までは、これらのリソースはすべてfinallyブロックを使用して閉じる必要があります。Java 7を使用している場合、リソースを閉じるには次のようにします。

try(Connection con = getConnection(url, username, password, "org.postgresql.Driver");
    Statement stmt = con.createStatement();
    ResultSet rs = stmt.executeQuery(sql);
) {

//statements
}catch(....){}

これで、con、stmt、およびrsオブジェクトがtryブロックの一部になり、Javaは使用後にこれらのリソースを自動的に閉じます。

お役に立てば幸いです。


ステートメントが暗黙的、つまりブロックResultSet rs = conn.createStatement().executeQuery(sql);内にある場合はどうなりtryますか?
Antares42 2015年

1
終了のためにfinally {}ブロックでそれらを参照することはできません。例外がスローされた場合、ResultSetのclose()メソッドは呼び出されません
Dan

それらを閉じないとどうなりますか?
Alex78191

それらを閉じないと、メモリリークが発生する可能性があります。
Yadu Krishnan

14

それだけで閉じるには十分であるStatementConnectionResultSetオブジェクトを明示的に閉じる必要はありません。

Javaのドキュメントは約について述べていjava.sql.ResultSetます:

ResultSetオブジェクトは、そのStatementオブジェクトが閉じられたとき、再実行されたとき、または複数の結果のシーケンスから次の結果を取得するために使用されたときに、それを生成したStatementオブジェクトによって自動的に閉じられます。


コメントについてBalusCに感謝します。「私はそれに依存しません。一部のJDBCドライバはそれに失敗します。」


25
私はそれに依存しません。一部のJDBCドライバーはその上で失敗します。たとえば、「最大オープンカーソル数を超えました」などのOracleの場合。開いているすべてのリソースを明示的に閉じるだけで、言い訳はありません。
BalusC 2013年

1
その場合、仕様に準拠していないドライバは使用しません
Enerccio

2
BalusCが指摘しているように、特定のプロバイダーへの依存関係をハードワイヤする代わりに、明示的に接続を閉じることは、防御的なプログラミングに適しています。
マイケルク2018

11

はい。結果セット、ステートメント、接続を閉じる必要があります。接続がプールからのものである場合、接続を閉じると、実際には再利用のためにプールに送り返されます。

通常、これはfinally{}ブロックで行う必要があります。そのため、例外がスローされた場合でも、これを閉じることができます。

多くのフレームワークが、このリソースの割り当て/割り当て解除の問題を処理します。例:SpringのJdbcTemplateApache DbUtilsには、nullであるかどうかにかかわらず、結果セット/ステートメント/接続を閉じる(および閉じるときに例外をキャッチする)ためのメソッドがあり、これも役立つ場合があります。


1
「最後の」日食を挿入すると、それが強調表示されて間違っていることがわかります。これはキャッチブロックの後に行くべきですか?
onaclov2000

はい。{} catch {} finally {}を試してください。catch {}はオプションです。ちょうど最後のように{}
ブライアンアグニュー

「close」ステートメントを最後に移動しましたが、「sqlexception」と言っているだけです。
onaclov2000

1
close()はSQLExceptionをスローします。あなたはそれを処理しなければなりません。これをサイレントに処理するには、DbUtils.closeQuietly()を参照してください。
Brian Agnew 2010

> conn.close()が発生しない場合、実際には何が起こっていますか?
Alex78191

8

実際には、try-with-resourcesブロックを使用することをお勧めします。tryブロックを終了すると、Javaがすべての接続を閉じます。

AutoClosableを実装するオブジェクトでこれを行う必要があります。

try (Connection connection = getDatabaseConnection(); Statement statement = connection.createStatement()) {
    String sqlToExecute = "SELECT * FROM persons";
    try (ResultSet resultSet = statement.execute(sqlToExecute)) {
        if (resultSet.next()) {
            System.out.println(resultSet.getString("name");
        }
    }
} catch (SQLException e) {
    System.out.println("Failed to select persons.");
}

getDatabaseConnectionの呼び出しは完了しました。これを、JDBC SQL接続またはプールからの接続を取得する呼び出しに置き換えます。


この場合、手動で接続を閉じる必要はありませんか?
コリンD

1
正しい。接続を明示的に閉じる必要はありません。tryコードブロックの最後に到達すると、閉じられます。
Joe

7

はい、接続を閉じる必要があります。それ以外の場合、データベースクライアントは通常、ソケット接続と他のリソースを開いたままにします。


...それが出るまで。これにより、クライアント側とサーバー側のさまざまな有限リソースが拘束されます。クライアントがこのようなことを行いすぎると、クライアント自体、データベースサービス、さらにはクライアントまたはサーバーマシンで実行されている他のアプリケーションに問題が発生する可能性があります。
スティーブンC
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.