実際にTomcat JDBC Poolを使用してみましょう。設定は非常に簡単です。
現在使用しているDataSourceを利用するResourceの設定に以下のようにfactory属性にorg.apache.tomcat.jdbc.pool.DataSourceFactoryを指定します。
<Resource name="jdbc/postgres" auth="Container"
type="javax.sql.DataSource"
factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
……
/>
以上で終了です。これで、DBCPの代わりにTomcat JDBC Poolが利用できます。
Resourceに設定されてあるその他のパラメータについては、前述の説明を参考に変更してください。基本的にそのままの設定でもマイグレーション可能です。アプリケーションには何の変更もありません。今まで通り利用できます。
Tomcat JDBC PoolではCommons DBCPと比べてJMXサポートでいくつかの改良が加えられています。上記で説明した各属性以外にも、コネクション取得待ちのスレッド数を取得するwaitcount属性や、checkIdle、checkAbandoned、testIdleなどのプール内のコネクションに対するバリデーションを、以下のようにJMX経由で行えます。
さらにjmxEnabledを有効にすることで、「tomcat.jdbc」ドメインでコネクションプールをMBeanとして登録できます。コネクションプールをJMXで登録することで、コネクションプールの属性やオペレーション以外にも、リスナによるJMX通知の受け取れます。
ちなみにTomcat JDBC Poolは標準で、コネクションプールの初期化失敗時や実コネクションの接続失敗時にそれぞれ通知します。
また、removeAbandonによるクローズ漏れコネクションに対する通知を、実際に破棄するときとsuspectTimeoutによる警告発生時の両方に通知します。
JdbcInterceptorはTomcat JDBC Poolに追加された最も大きな機能の1つです。JdbcInterceptorはDBアクセスをインターセプトし、なんらかの処理を追加するために利用されます。JdbcInterceptorは自分で独自のものを作成できますし、Tomcatがデフォルトで用意しているものも利用できます。
まずはTomcatがデフォルトで用意しているJdbcInterceptorを5つ紹介します。
コネクション属性のautoCommit, readOnly, transactionIsolationをキャッシュするJdbcInterceptorです。
これらの属性のsetterやgetterが呼ばれたときにキャッシュを利用することでデータベースとの余分なやりとりを避けられます。
createStatement、prepareStatement、prepareCallを使用して作成されたすべてのステートメントを追跡して、コネクションがプールに返却される際にこれらのステートメントをcloseします。
ステートメントをキャッシュするJdbcInterceptorです。
Slowクエリを報告するためのJdbcInterceptorです。Slowクエリの報告にJMX通知を利用したSlowQueryReportJmxも利用可能です。
クローズ漏れコネクション検知までのタイマーをリセットするJdbcInterceptorです。removeAbandonedTimeoutを小さい値に設定しており、コネクションを多くの回数利用するバッチプログラムなどで利用されます。
次に、JdbcInterceptorの設定方法を紹介します。jdbcInterceptors属性にセミコロン区切りでJdbcInterceptorを指定してください。
通常はFQCNで指定しますが、単にクラス名だけの指定も可能です。その場合は「org.apache.tomcat.jdbc.pool.interceptor.」がパッケージが自動的に付与されます。また、「jdbcInterceptors="StatementFinalizer(useEquals=true)" 」のようにプロパティ値も同時に指定可能です。
最後に、JdbcInterceptorを作成方法を説明します。まずは簡単なサンプルをご覧ください。
public class SampleInteceptor extends JdbcInterceptor {
protected PooledConnection connection = null;
protected ConnectionPool pool = null;
@Override
public void reset(ConnectionPool pool, PooledConnection connection) {
this.pool = pool;
this.connection = connection;
// initialize or finalize
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// do something
return super.invoke(proxy,method,args);
}
}
「public class SampleInteceptor extends JdbcInterceptor {」でサンプルクラスは「org.apache.tomcat.jdbc.pool.JdbcInterceptor」クラスを継承します。
「public void reset(ConnectionPool pool, PooledConnection connection) {」では、抽象メソッドの「reset(ConnectionPool, PooledConnection)」を実装しています。resetメソッドはコネクションプールからコネクションを取得した際の初期化処理として呼び出されます。
また、コネクションクローズ時にも引数にnullが指定された状態で終了処理として呼び出されます。自作のJdbcInterceptorの初期化&終了処理を実装してください。
以上が、JdbcInterceptorの作成における最低限やらなくてはならないことです。
その他のJdbcInterceptorのメソッドは任意でオーバーライドします。では、どのようなメソッドがあるか紹介します。
invokeメソッドはコネクションに対する操作が呼び出されたときに実行されます。
特定の操作の前後に任意の処理を差し込めます。メソッド名の比較にはJdbcInterceptor#compareメソッドを使用します。
また、JdbcInterceptorはそれぞれチェーンでつながっているので、次のJdbcInterceptorに処理をつなげたい場合は、サンプルのように「super.invoke(proxy,method,args)」で次のJdbcInterceptorを呼び出す必要があります。処理を終了させたい場合は、「super.invoke(proxy,method,args)」を呼び出す必要はありません。
disconnectedメソッドは実コネクションが切断されたときに呼び出されます。
poolStartedメソッドはコネクションプールの起動時に呼び出されます。
poolClosedメソッドはコネクションプールのclose時に呼び出されます。
最後に紹介するのはコネクションの非同期取得です。Tomcat JDBC Poolでは非同期でコネクションを取得できます。コードはこんな感じです。
……
Future future = datasource.getConnectionAsync();
while (!future.isDone()) {
// Connection is not yet available.
// do something.
try {
Thread.sleep(100);
}catch (InterruptedException x) {
Thread.currentThread().interrupted();
}
}
con = future.get();
……
コネクションが取得できるまで、別処理ができます。しかし、Tomcat JDBC Poolにものすごく依存してしまうので、使いどころが難しいですね。
以上でTomcat JDBC Poolの説明は終わりです。Tomcat JDBC Poolは、いかがでしたでしょうか?
Commons DBCPからほとんど変更なくTomcat JDBC Poolに移行できま、さらに、JMXサポートの拡張による外部からコネクションプールのバリデーションや、JdbcInterceptorによるDB処理へ独自の処理を追加しカスタマイズできるなど、さまざまな改良が加えられています。
ソースコードもCommons DBCPと比べると非常にシンプルです。リリース間隔もTomcatと同時に行われるので、DBCPよりも大分速いでしょう。バグ修正されたものの、いつまでたっても修正版がリリースされないということはありません。
良いことばかりのように見えるTomcat JDBC Poolですが、利用実績でいうとCommons DBCPに到底およびません。これからいろいろなところで利用され、実績も増えていくのではないでしょうか。
Copyright © ITmedia, Inc. All Rights Reserved.