今回も、前回「Commonsでオブジェクトプーリングを実現」に引き続きCommonsプロジェクトの活用法を紹介します。前回はPoolを利用してデータベースのコネクションプーリングを実現しました。今回はDBCPを用いて、より容易なデータベースのコネクションプーリングを実現してみましょう。なお、この原稿執筆時点でのDBCPコンポーネントの最新バージョンは1.0です。
PoolingDriverクラスとPoolingDataSourceクラス
通常JDBCを用いたプログラミングではConnectionオブジェクト(java.sql.Connection)を使ってデータベースにアクセスしますが、Connectionオブジェクトを取得するにはDriverオブジェクト(java.sql.Driver)やDataSourceオブジェクト(javax.sql.DataSource)が必要になります。DBCPではこれらのクラスに対応するPoolingDriverクラス(org.apache.commons.dbcp.PoolingDriver)とPoolingDataSourceクラス(org.apache.commons.dbcp.PoolingDataSource)が用意されています。DBCPを用いたプログラミングでは、まずこれらのクラスのいずれかのインスタンスを生成し、生成したインスタンスからConnectionオブジェクトを取得することになります。
ただし、これらのクラスのインスタンスを利用するためにはあらかじめObjectPoolオブジェクトを与えておく必要があります。実はDBCPコンポーネントはPoolコンポーネントのオブジェクトプーリング機能を利用してコネクションプーリング機能を実現していますので、DBCPコンポーネントを利用するには前回説明したPoolコンポーネントのObjectPoolオブジェクトやPoolableObjectFactoryオブジェクトを用意する必要があるのです。
PoolingDriverやPoolingDataSourceに与えるObjectPoolとしては、Poolが提供しているObjectPool実装クラスを利用することができます。また、前回に説明しましたようにObjectPoolを利用するためにはPoolableObjectFactoryインターフェイスの実装クラスを用意する必要がありますが、これに関してはDBCP側で用意してくれています。それがPoolableConnectionFactoryクラス(org.apache.commons.dbcp.PoolableConnectionFactory)です。
ConnectionFactoryクラス
PoolableConnectionFactoryにはConnectionオブジェクトを生成するためのクラスとしてConnectionFactoryインターフェイス(org.apache.commons.dbcp.ConnectionFactory)の実装クラスを与える必要があります。ConnectionFactoryインターフェイスの実装クラスとしてはDriverConnectionFactory、DriverManagerConnectionFactory、DataSourceConnectionFactoryの3つ(すべてorg.apache.commons.dbcpパッケージ)が用意されています。
DBCPの使用例
ここではDBCPの使用例として、Poolの使用例で説明したWebアプリケーションをDBCPを利用するように書き直したものについて説明します。書き直したコードは、前回のサンプルコードのアーカイブに含まれているindex2.jspです。
DBCPのコネクションプールを利用するための準備として、index2.jspのjspInit()メソッド中でPoolingDataSourceまたはPoolingDriverクラスのインスタンスを生成します(リスト1)。Poolの例ではこのメソッド中でObjectPoolのインスタンスを生成しましたが、DBCPではObjectPoolインスタンスを生成したうえでそれをPoolingDataSourceまたはPoolingDriverインスタンスに与えます。
*** 一部省略されたコンテンツがあります。PC版でご覧ください。 ***
順を追って見ていきましょう。まずObjectPoolのインスタンス(ここではStackObjectPool)を生成します(1)。ここで注意したいのは、前回説明したPoolの例ではコンストラクタにPoolableObjectFactoryインスタンスを渡したのに対してDBCPの場合は引数なしのコンストラクタを呼び出すということです。これに関しては後ほど説明します。
次にConnectionオブジェクトを生成するためのConnectionFactoryのインスタンスを生成します(2)。ここではDriverManagerConnectionFactoryを用いています(なお、このクラスのコンストラクタは引数としてDriverManager#getConnection()メソッドと同じもの、すなわちデータベース接続用のURLとユーザー名とパスワードを取りますので、DriverManagerクラスを置き換える場合はDriverManagerConnectionFactoryを使用すると楽です)。
次はObjectPoolに与えるPoolableObjectFactoryインスタンスとして、コネクションプール用に用意されているPoolableConnectionFactoryインスタンスを生成します(3)。このときコネクションプールの振る舞いを決定するような各種パラメータをコンストラクタに指定することができます。コンストラクタPoolableConnectionFactory(connFactory、pool、stmtPoolFactory、validationQuery、defaultReadOnly、defaultAutoCommit)のそれぞれの引数の意味を表1にまとめておきます。
引数 | 説明 | |
---|---|---|
connFactory Connection | オブジェクトを生成するためのConnectionFactoryインスタンス | |
pool | Connectionのプーリングに用いるObjectPoolインスタンス | |
stmtPoolFactory | PreparedStatementオブジェクトをプーリングする場合、プーリング用のKeyedObjectPoolオブジェクトを生成するためのKeyedObjectPoolFactoryインスタンス。PreparedStatementオブジェクトをプーリングしない場合はnullを指定 | |
validationQuery | Connectionが有効であるかどうかを検査するためのSQL文 | |
defaultReadOnly | プールから取り出されたConnectionを読み込み専用にする | |
defaultAutoCommit | プールから取り出されたConnectionを自動コミットモードにする |
なお生成したPoolableConnectionFactoryオブジェクトに関しては、コンストラクタの内部でObjectPool#setFactory()メソッドが呼ばれることで自動的にObjectPoolと関連付けられます。このためObjectPoolインスタンスの生成時にコンストラクタにPoolableObjectFactoryオブジェクトを渡さなくてもよかったのです。
最後にPoolingDataSourceクラスのインスタンスを生成します(4)。このとき、最初に生成したObjectPoolオブジェクト(StackObjectPool)をコンストラクタの引数として渡します。これでコネクションプールのためのDataSourceオブジェクトの準備ができました。
このようにして準備したコネクションプールを使用する部分のコードをリスト2に示します。作成したPoolingDataSourceはDataSourceインターフェイスを実装していますので、通常のDataSourceを扱うのと同様にgetConnection()メソッドを用いてConnectionを取り出すことができます(5)。また、取り出したConnectionオブジェクトをプールに戻すには、ObjectPool#returnObject()を用いるのではなく単にConnection#close()メソッドを呼び出せばよいようになっています(6)。というのは実はPoolingDataSourceが実はConnectionオブジェクトのラッパオブジェクトを返すようになっていて、このラッパオブジェクトのclose()メソッドがオブジェクトプールへのConnectionの返却処理を行ってくれるようになっているのです。このように、DBCPではPoolを直接用いてコネクションプールを実装した場合とは違って、コネクションプールを利用していることを全く意識せずにConnectionを使用することができるようになっています。
*** 一部省略されたコンテンツがあります。PC版でご覧ください。 ***
プーリングについてのまとめ
前回と今回とでPoolコンポーネントとDBCPコンポーネントをご紹介しました。上層のアプリケーション開発時にこれらのコンポーネントを直接使用する機会は多くないかもしれませんが、ミドルウェア寄りのシステム開発などでは使用する場面もあるかと思います。またこれらのコンポーネントはStrutsのようなJakartaのほかのプロダクトでも用いられていますので、仕組みを覚えておくと役に立つこともあるかと思います。
次回はJavaコレクションフレームワークを拡張するCollectionsコンポーネントとCommonsの中でもユーティリティ色の強いLangコンポーネントについて説明します。
筆者プロフィール
横田健彦(よこた たけひこ)
東京工業大学卒業後、(株)東芝に入社。現在、知識メディアラボラトリーにてコミュニティベース情報共有システムの研究に従事。小学校のころからコンピュータに触れ、主にゲームプログラミングを通してBASIC、アセンブラをはじめとする多数の言語を学ぶ。JavaではJakartaプロジェクトの成果物を利用していく中で主にWebアプリケーションプログラミングの面白さに引かれ、Ja-Jakartaプロジェクトの活動に貢献する一方でオープンソースのJavaベースのWebコンテンツ管理システムであるKvasir/Soraの開発を行っている。
Copyright © ITmedia, Inc. All Rights Reserved.