web-dev-qa-db-ja.com

プール内のJDBC接続を閉じる

JDBCを使用するための標準コードセクションは...

Connection conn = getConnection(...);
Statement  stmt = conn.conn.createStatement (ResultSet.TYPE_SCROLL_INSENSITIVE,
                                                ResultSet.CONCUR_READ_ONLY);
ResultSet  rset = stmt.executeQuery (sqlQuery);

// do stuff with rset

rset.close(); stmt.close(); conn.close();

質問1:接続プールを使用する場合、最後に接続を閉じる必要がありますか?もしそうなら、プーリングの目的は失われていませんか?そうでない場合、Connectionの特定のインスタンスが解放されて再利用できる場合、DataSourceはどのように知るのですか?私はこれについて少し混乱していますが、どんなポインタもありがたいです。

質問2:次の方法は標準に近いものですか?プールから接続を取得しようとしているように見えます。DataSourceを確立できない場合は、旧式のDriverManagerを使用してください。実行時にどの部分が実行されるのかさえわかりません。上記の質問を繰り返して、そのようなメソッドから出てくる接続を閉じる必要がありますか?

ありがとう、MS。

synchronized public Connection getConnection (boolean pooledConnection)
                                                        throws SQLException {
        if (pooledConnection) {
                if (ds == null) {
                        try {
                                Context envCtx = (Context)
                                        new InitialContext().lookup("Java:comp/env");
                                ds = (DataSource) envCtx.lookup("jdbc/NamedInTomcat");
                                return ds.getConnection();
                        } catch (NamingException e) {
                                e.printStackTrace();
                }}
                return (ds == null) ? getConnection (false) : ds.getConnection();
        }
        return DriverManager.getConnection(
                "jdbc:mysql://"+ipaddy+":"+dbPort +"/" + dbName, uName, pWord);
}

編集:スタックトレースが表示されないため、プールされた接続を取得していると思います。

100

接続プールを使用する場合、最後に接続を閉じる必要がありますか?もしそうなら、プーリングの目的は失われていませんか?そうでない場合、Connectionの特定のインスタンスが解放されて再利用できる場合、DataSourceはどのように知るのですか?私はこれについて少し混乱していますが、どんなポインタも高く評価しています。

はい、確かにプールされた接続も閉じる必要があります。実際には、実際の接続のラッパーです。カバーの下で実際の接続を解放してプールに戻します。実際の接続を実際に閉じるか、新しいgetConnection()呼び出しで再利用するかを決定するのは、プール次第です。そのため、接続プールを使用しているかどうかに関係なく、always取得したfinallyブロックのtryブロックの逆順ですべてのJDBCリソースを閉じる必要があります。 Java 7では、 try-with-resources ステートメントを使用して、これをさらに簡素化できます。


次の方法は標準に近いものですか?プールから接続を取得しようとしているように見えます。DataSourceを確立できない場合は、旧式のDriverManagerを使用してください。実行時にどの部分が実行されるのかさえわかりません。上記の質問を繰り返して、そのようなメソッドから出てくる接続を閉じる必要がありますか?

例はかなり怖いです。 DataSourceをルックアップ/初期化する必要があるのは、アプリケーション全体のDB構成クラスのコンストラクター/初期化で、アプリケーションの起動中に1回だけです。次に、アプリケーションの存続期間中、同じデータソースでgetConnection()を呼び出すだけです。同期もnullチェックも必要ありません。

こちらもご覧ください:

113
BalusC

プールは通常、ラップされたConnectionオブジェクトを返します。この場合、close()メソッドはオーバーライドされ、通常はプールにConnectionを返します。 close()の呼び出しは問題なく、おそらく必要です。

Close()メソッドはおそらく次のようになります。

public void close() throws SQLException {
  pool.returnConnection(this);
}

2番目の質問では、ロガーを追加して、一番下のブロックが実行されるかどうかを表示できます。データベース接続の設定にどちらか一方しか必要ないのではないかと想像します。データベースアクセスにはプールのみを使用します。いずれにしても、リークを防ぐためには、接続を閉じることが非常に重要です。

21
taer

実際、接続管理への最善のアプローチは、それらをどこのコードにもファームアウトしないことです。

接続を開いたり閉じたりする唯一の場所であるSQLExecutorクラスを作成します。

その後、アプリケーションの残りの部分全体が、プールから接続を取得して場所全体を管理(または誤管理)するのではなく、エグゼキュータにステートメントを送り込みます。

Executorのインスタンスは必要な数だけ持つことができますが、自分のために接続を開いたり閉じたりするコードを誰も書いてはいけません。

便利なことに、これにより、単一のコードセットからすべてのSQLを記録することもできます。

0