連載
» 2011年11月07日 00時00分 公開

Tomcat 7の新機能で何ができるようになるのか?(番外編):Commons DBCPを超えるTomcat JDBC Poolとは (2/2)

[藤野圭一,NTT OSSセンタ]
前のページへ 1|2       

Tomcat JDBC Poolを使うには

 実際にTomcat JDBC Poolを使用してみましょう。設定は非常に簡単です。

Resourceの設定を少し変えるだけ

  現在使用している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に設定されてあるその他のパラメータについては、前述の説明を参考に変更してください。基本的にそのままの設定でもマイグレーション可能です。アプリケーションには何の変更もありません。今まで通り利用できます。

拡張されたJMXサポート

 Tomcat JDBC PoolではCommons DBCPと比べてJMXサポートでいくつかの改良が加えられています。上記で説明した各属性以外にも、コネクション取得待ちのスレッド数を取得するwaitcount属性や、checkIdle、checkAbandoned、testIdleなどのプール内のコネクションに対するバリデーションを、以下のようにJMX経由で行えます。

  • checkIdle:アイドル状態でminIdle以上のコネクションに対してのバリデーションを実行
  • checkAbandoned:クローズ漏れコネクションの破棄を実行
  • testIdle:全てのアイドルコネクションに対してバリデーションを実行

 さらにjmxEnabledを有効にすることで、「tomcat.jdbc」ドメインでコネクションプールをMBeanとして登録できます。コネクションプールをJMXで登録することで、コネクションプールの属性やオペレーション以外にも、リスナによるJMX通知の受け取れます。

 ちなみにTomcat JDBC Poolは標準で、コネクションプールの初期化失敗時や実コネクションの接続失敗時にそれぞれ通知します。

 また、removeAbandonによるクローズ漏れコネクションに対する通知を、実際に破棄するときとsuspectTimeoutによる警告発生時の両方に通知します。

DBアクセスを拡張する「JdbcInterceptor」とは

 JdbcInterceptorはTomcat JDBC Poolに追加された最も大きな機能の1つです。JdbcInterceptorはDBアクセスをインターセプトし、なんらかの処理を追加するために利用されます。JdbcInterceptorは自分で独自のものを作成できますし、Tomcatがデフォルトで用意しているものも利用できます。

 まずはTomcatがデフォルトで用意しているJdbcInterceptorを5つ紹介します。

【1】org.apache.tomcat.jdbc.pool.interceptor.ConnectionState

 コネクション属性のautoCommit, readOnly, transactionIsolationをキャッシュするJdbcInterceptorです。

 これらの属性のsetterやgetterが呼ばれたときにキャッシュを利用することでデータベースとの余分なやりとりを避けられます。

【2】org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer

 createStatement、prepareStatement、prepareCallを使用して作成されたすべてのステートメントを追跡して、コネクションがプールに返却される際にこれらのステートメントをcloseします。

【3】org.apache.tomcat.jdbc.pool.interceptor.StatementCache

 ステートメントをキャッシュするJdbcInterceptorです。

【4】org.apache.tomcat.jdbc.pool.interceptor.SlowQueryReport

 Slowクエリを報告するためのJdbcInterceptorです。Slowクエリの報告にJMX通知を利用したSlowQueryReportJmxも利用可能です。

【5】org.apache.tomcat.jdbc.pool.interceptor.ResetAbandonedTimer

 クローズ漏れコネクション検知までのタイマーをリセットするJdbcInterceptorです。removeAbandonedTimeoutを小さい値に設定しており、コネクションを多くの回数利用するバッチプログラムなどで利用されます。

JdbcInterceptorの使い方

 次に、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のメソッドは任意でオーバーライドします。では、どのようなメソッドがあるか紹介します。

【1】public Object invoke(Object proxy, Method method, Object[] args)

 invokeメソッドはコネクションに対する操作が呼び出されたときに実行されます。

特定の操作の前後に任意の処理を差し込めます。メソッド名の比較にはJdbcInterceptor#compareメソッドを使用します。

 また、JdbcInterceptorはそれぞれチェーンでつながっているので、次のJdbcInterceptorに処理をつなげたい場合は、サンプルのように「super.invoke(proxy,method,args)」で次のJdbcInterceptorを呼び出す必要があります。処理を終了させたい場合は、「super.invoke(proxy,method,args)」を呼び出す必要はありません。

【2】public void disconnected(ConnectionPool parent, PooledConnection con, boolean finalizing)

 disconnectedメソッドは実コネクションが切断されたときに呼び出されます。

【3】public void poolStarted(ConnectionPool pool)

 poolStartedメソッドはコネクションプールの起動時に呼び出されます。

【4】public void poolClosed(ConnectionPool pool)

 poolClosedメソッドはコネクションプールのclose時に呼び出されます。

コネクションの非同期取得「getConnectionAsync」

 最後に紹介するのはコネクションの非同期取得です。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に到底およびません。これからいろいろなところで利用され、実績も増えていくのではないでしょうか。

 今回のソースコードは、こちらからダウンロードできます

前のページへ 1|2       

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。