2017-03-23 3 views
0

Tomcat WebアプリケーションにJDBCプールを使用しています。JDBCプール - 正しく使用する方法

私はdocsで読んだので、私は接続を取得し、クエリを実行して閉じる必要があります。 終了後、接続はプールに戻ります。

私は、クエリDBが外部イベントに依存し、毎5秒ごとに2つの正しい動作をするタスクの方が良いと思います。

誰かが5秒ごとに繰り返すタスクの使用方法を説明できますか?

PS:コードで余分なチェックをスキップして、コードを読みやすくします。

ウェイ#1は、プールからの接続と近い5秒毎

Connection c = null; 
Statement s = null; 
ResultSet rs = null; 
DataSource ds = ... Get DataSource ... 

while(running) { 
    try { 
     c = ds.getConnection(); 
     s = c.createStatement(); 
     rs = s.executeQuery('SELECT data FROM my_table'); 
     ... do something with result ... 
    } catch (SQLException sec) { 
     ... print exception ... 
    } finally { 
     try { 
      rs.close(); 
      s.close(); 
      c.close(); 
     } catch (SQLException sec) { ... print exception ... } 

     ... Thread sleep 5 seconds and repeat ... 
    } 
} 

ウェイ#2ループ前に接続を取得し、クローズした後、ループ内で再接続

Connection c = null; 
Statement s = null; 
ResultSet rs = null; 
DataSource ds = ... Get DataSource ... 

c = ds.getConnection(); 

while(running) { 
    try { 
     s = c.createStatement(); 
     rs = s.executeQuery('SELECT data FROM my_table'); 
     ... do something with result ... 
    } catch (SQLException sec) { 
     ... print exception ... 
     ... if connection lost, try reconnect and execute query again ... 
    } finally { 
     try { 
      rs.close(); 
      s.close(); 
     } catch (SQLException sec) { 
      ... print exception ... 
     } 
     ... Thread sleep 5 seconds and repeat ... 
    } 
} 

c.close(); 

プールの設定を取得します。

<Resource name="jdbc/pg_mega" auth="Container" 
     type="javax.sql.DataSource" driverClassName="org.postgresql.Driver" 
     url="jdbc:postgresql://127.0.0.1:6432/db" 
     factory="org.apache.tomcat.jdbc.pool.DataSourceFactory" 
     username="***" password="****" 
     defaultAutoCommit="true" 
     initialSize="1" 
     maxActive="300" 
     maxTotal="300" 
     maxIdle="20" 
     minIdle="5" 
     maxWait="10000" 
     validationQuery="select 1" 
     validationInterval="30000" 
     testWhileIdle="false" 
     testOnBorrow="true" 
     testOnReturn="false" 
     timeBetweenEvictionRunsMillis="30000" 
     minEvictableIdleTimeMillis="30000" 
     /> 
+0

大きなデータや非同期プロセスを処理しているのでなければ、なぜ私はスレッドアプリケーションをスリープ状態にしているのか分かりません。 2番目のアプローチはよさそうです。ループの各繰り返しで接続を取得する必要はありません。 – notionquest

+0

統計情報を集めるBeanからのこのコード、Webアプリケーションの一部 – Dmitry

+2

もう1つのオプションは、その目的のために1つの接続を完全に予約します。最初のスレッドは、そのスレッドがスレッドを使用していない間に、他のスレッドが接続を使用できるようにします。それはおそらく大きな違いはありません。あなたはwhile/sleepシステムの代わりに適切なスケジューラーを使うべきです。 – Kayaman

答えて

1

私が最も一般的なパターンはこのだと思う:私はあなたの上のJava 7から、あまりにも多くの決まり文句なしに安全に近いこれらのヘルパー関数を使用し

Connection conn = null; 
    PreparedStatement stmt = null; 
    ResultSet res = null; 
    try { 
     conn = ds.getConnection(); 
     stmt = conn.prepareStatement(sqlStatement); 
     // 
     // .... 
     res = stmt.executeQuery(); 

     // use the resultset 

     conn.commit(); 
    } catch (SQLException e) { 
     // Manage the exception 
     try { 
      conn.rollback(); 
     } catch (SQLException e1) { 
      // SWALLOW 
     } 

    } finally { 
     close(res); 
     close(stmt); 
     close(conn); 
    } 

はので、これらのヘルパーはもう何も使用しないオートクローズすることができます。

public static void close(Connection conn) { 
    try { 
     if (conn != null) 
      conn.close(); 
    } catch (SQLException e) { 
     // SWALLOW 
    } 
} 

public static void close(Statement stmt) { 
    try { 
     if (stmt != null) 

      stmt.close(); 
    } catch (SQLException e) { 
     // SWALLOW 
    } 
} 

public static void close(ResultSet res) { 
    try { 
     if (res != null) 
      res.close(); 
    } catch (SQLException e) { 
     // SWALLOW 
    } 
} 

あなたはRSがあなたの例ではNULLである場合(例えば)接続を閉じ、そしてない場合は、本当に、悪いことが起こるfinally文で接続を閉じてくださいする必要があります(そう難しいことではありません)接続を閉じることはありません。

プールからの接続の取得と解放はパフォーマンス上の問題ではありません。マイクロ秒で実行され、何千回も高速に実行されます。

あなたは接続を熱心に解放しない理由はトランザクションです。あなたはトランザクション全体で同じ接続を維持したい(これを回避することはできません)。

コミット(またはロールバック)すると、その特有の接続はもう必要ないので、解放してください。

もう一つのヒント、ランタイム例外と(あなたがキャッチしません)でもエラーが常に存在しているので、あなたはSQL例外をキャッチした場合でも、最終的に接続を閉じますが、最終的にでもOutOfMemoryErrorが発生またはClassDefNotFoundErrorの顔に実行されますまたは他のいずれかに接続し、接続がプールに戻されます。

最後に、接続が切断された場合に再接続を試みるプールがあります。実際にはプールは無効な接続を破棄し、必要に応じて新しいバッチを作成します。

接続の有効性を検証するには、適切なポリシーを選択する必要があります。不適切な選択を行うと、パフォーマンスが低下したり、プールから取得された無効な接続に起因する例外が発生します。プールの最適化

は、他の多くのパフォーマンス・チューニング・タスクのようなものです:HARD

たとえば、 testOnBorrow="true"は、接続を取得する前にDBにヒットしますが、安全ですが、借りているかどうかチェックしないと、数十時間または数百時間かかることがあります。

testWhileIdle="true"は安全性が低いです(無効な接続になる可能性がありますが)はるかに速く、接続を維持できる利点があります。

接続の使い方、エラーの処理方法、DBの場所(同じマシン上、LAN上、弱い場所)、その他多くの要因を考慮して選択する必要があります。

1

プールを使用する場合、Way#2は正しくありません。プールを使用する場合は、プールの使用を最大限に活用するために、プールからの接続をできるだけ短く(「リース」)してください。プールを使用しない場合は、接続の作成と破棄、および接続のライフサイクルの管理にかかるコストを考慮する必要があります。

プールを使用する場合は、常にリース接続をプールに戻す必要があります(接続を閉じるときに接続がプールに返されます)。接続がプールに返されない場合(つまり接続がリークされた場合)、プールはすぐに空になり、アプリケーションは動作を停止します。これは、状況が悪い場合に特に重要です(たとえば、コード例では、rsnullであるため、クエリエラーが原因で接続がリークします)。接続漏れを防ぐには、接続漏れに対する保護機能を内蔵したSql2oのようなツールを使用することを検討してください。

また、プール内の接続数を減らしてください。 minIndle="1"maxActive="4"で始まります。ストレステストを使用してプールサイズの上限を判断してください(プール内の接続のほうが通常よりも害よりも害があります)。About Pool SizingからHikariCPにデータベース接続プールに関する記事があります。

関連する問題