質問

私は、ペット プロジェクトの 1 つでコード レビュー (主に FindBugs などのツールを使用) を行っていましたが、FindBugs によって次のコードがエラー (疑似コード) としてマークされました。

Connection conn = dataSource.getConnection();

try{
    PreparedStatement stmt = conn.prepareStatement();
    //initialize the statement
    stmt.execute();
    ResultSet rs =  stmt.getResultSet();
    //get data
}finally{
    conn.close();
}

このコードではリソースが解放されない可能性があるというエラーが発生しました。ResultSet と Statement が閉じられていないことがわかったので、最終的にそれらを閉じました。

finally{
    try{
        rs.close()
    }catch(SqlException se){
        //log it
    }
    try{
        stmt.close();
    }catch(SqlException se){
        //log it
    }
    conn.close();
}

しかし、私は多くのプロジェクト (かなりの数の企業の) で上記のパターンに遭遇しましたが、誰も ResultSet や Statements を閉じていませんでした。

接続が閉じられたときに ResultSet と Statements が閉じられないという問題が発生しましたか?

だけ見つけました これ これは、Oracle が接続を閉じるときに ResultSet を閉じる際に問題があることを示しています (Oracle データベースを使用しているため、修正しました)。java.sql.api は Connection.close() javadoc で何も述べません。

役に立ちましたか?

解決

結果セットではなく接続のみを閉じる場合の問題の 1 つは、接続管理コードが接続プーリングを使用している場合、 connection.close() 接続をプールに戻すだけです。さらに、一部のデータベースではサーバー上にカーソル リソースがあり、明示的に閉じない限り適切に解放されません。

他のヒント

接続が閉じられているにもかかわらず、Oracle で閉じられていない ResultSet に関する問題が発生しました。私が得たエラーは

"ORA-01000: maximum open cursors exceeded"

それで:ResultSet は常に閉じてください。

常にすべての JDBC リソースを明示的に閉じる必要があります。アーロンとジョンがすでに述べたように、接続を閉じると接続はプールに戻されるだけであり、すべての JDBC ドライバーがまったく同じ方法で実装されるわけではありません。

以下は、finally ブロックから使用できるユーティリティ メソッドです。

public static void closeEverything(ResultSet rs, Statement stmt,
        Connection con) {
    if (rs != null) {
        try {
            rs.close();
        } catch (SQLException e) {
        }
    }
    if (stmt != null) {
        try {
            stmt.close();
        } catch (SQLException e) {
        }
    }
    if (con != null) {
        try {
            con.close();
        } catch (SQLException e) {
        }
    }
}

この場合、Oracle はオープン カーソルに関するエラーを表示します。

によると: http://java.sun.com/javase/6/docs/api/java/sql/Statement.html

ステートメントを再利用すると開いている結果セットがすべて閉じられ、ステートメントを閉じると結果セットがすべて閉じられるようですが、接続を閉じると作成されたリソースがすべて閉じることについては何も表示されません。

これらの詳細はすべて JDBC ドライバー プロバイダーに委ねられます。

すべてを明示的に閉じることが常に最も安全です。try{ xxx } catch (Throwable {}) ですべてをラップする util クラスを作成しました。これにより、close scan がスローすると思われる例外を気にせずに、Utils.close(rs) や Utils.close(stmt) などを呼び出すことができます。 。

ODBC ブリッジは、一部の ODBC ドライバーでメモリ リークを引き起こす可能性があります。

優れた JDBC ドライバーを使用している場合は、接続を閉じる際に問題は発生しません。しかし、問題が 2 つあります。

  • 優秀なドライバーがいるかどうか知っていますか?
  • 将来的に他の JDBC ドライバーを使用する予定ですか?

ベストプラクティスはすべてを閉じることです。

私は大規模な J2EE Web 環境で作業しています。1 回のリクエストで接続できるデータベースが複数あります。一部のアプリケーションで論理デッドロックが発生し始めました。問題は次のようなものでした。

  1. ユーザーはページをリクエストします
  2. サーバーは DB 1 に接続します
  3. サーバーは DB 1 を選択します
  4. サーバーが DB 1 への接続を「閉じる」
  5. サーバーは DB 2 に接続します
  6. 行き詰まった!

これは 2 つの理由で発生しました。通常よりもはるかに大量のトラフィックが発生していたことと、デフォルトの J2EE 仕様では、スレッドの実行が終了するまで実際に接続を閉じませんでした。したがって、上記の例では、最終的に接続が適切に閉じられたとしても、ステップ 4 は実際には接続を閉じませんでした。

これを修正するには、データベース接続の web.xml でリソース参照を使用し、res-sharing-scope を unsharable に設定する必要があります。

例:

<resource-ref>
    <description>My Database</description>
    <res-ref-name>jdbc/jndi/pathtodatasource</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
    <res-sharing-scope>Unshareable</res-sharing-scope>
</resource-ref>

閉じられていない ResultSet に関する問題を確かに見たことがありますが、それらを常に閉じていると何が問題になるでしょうか?これを忘れずに行う必要があるという信頼性のなさが、これらの詳細を管理するフレームワークに移行する最大の理由の 1 つです。開発環境では実現できないかもしれませんが、Spring を使用して JPA トランザクションを管理するのは非常に幸運でした。接続、ステートメント、結果セットのオープン、および過度に複雑な try/catch/finally ブロックの作成に関する厄介な詳細 (try/catch ブロックを使用) ファイナルブロックで!) 再度閉じると表示されなくなるだけなので、実際に作業を行う必要があります。そのようなソリューションに移行することを強くお勧めします。

Java では、ステートメント (結果セットではない) が Oracle のカーソルに関連付けられます。JVM およびシステム リソースに関して予期しない動作が発生する可能性があるため、開いたリソースは閉じることをお勧めします。

さらに、一部の JDBC プーリング フレームワークはステートメントと接続をプールするため、それらを閉じないと、それらのオブジェクトがプール内で空きとしてマークされず、フレームワークでパフォーマンスの問題が発生する可能性があります。

一般に、オブジェクトに close() または destroy() メソッドがある場合、それを呼び出す理由があり、無視する場合は自己責任で行ってください。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top