ここではTOMCAT上で稼働するJavaプログラムからデータベースを操作するとき、データベースとの接続にコネクションプール:DBCP(DataBase Connection Pool)という仕組みを使う方法について説明します。
Javaプログラムからデータベースにアクセスする場合で、JDBCを使った例で手順を説明すると次のようになります。
-
Class.forName(対象JDBCドライバ)でJDBCドライバをロード
-
DriverManager.getConnection(接続先DB, 接続ユーザーID, 接続パスワード)でDBに接続し、コネクション(Connection):接続を取得
-
取得したコネクション:接続からStatementを生成し、SQL文を設定して実行
-
処理終了後にStatementをClose
-
続いてコネクション(Connection):接続をCloseしてDBから切断
この中でパフォーマンス面で問題になり得るのが2と5、データベースへの接続と切断です。
例えばあるクライアント画面からのリクエストで結果表示画面を作成するのに、6個のテーブルアクセスが必要だとします。
テーブルやビュー単位にクラスを分けていることを想定すると、この結果表示画面作成に複数のデータベースアクセスクラスが実行されます。個々のクラス内で別個にデータベース接続・切断を実装しているとすると、処理単位の細かい接続・切断処理が複数実行されてしまいます。
さらに複数クライアントからの同時処理を考えると、この接続・切断処理がかなりの頻度発生します。そしてこのデータベース接続・切断処理はそこそこオーバーヘッドが掛かるので(とくにAPサーバーとDBサーバーが別サーバーのとき)、あまり頻度が高いとパフォーマンス上馬鹿になりません。
一つの解決策としては個々のクラスで個別にデータベース接続・切断を行うのではなく、業務処理コントロールを担当するクラスで行う方法です。そして業務処理コントロールクラスからデータベースアクセスクラスを呼び出すときに、引数としてコネクション:接続を渡します。
こうすることによって一つのコネクション:接続を、複数クラス間で使いまわすのです。
別の方法がDBCP(DataBase Connection Pool)を使う方法です。これはデータベースへのコネクションを個々のクラスで個別に取得するのではなく、あらかじめ確保済みのコネクション(Pooled Connection)を使いまわす方法です。
DBCPを使う場合はデータベースコネクションの管理は、J2EE実行環境であるAPサーバーが行うように設定します。複数(設定内容による)のコネクション:接続を最初にまとめて確保しておき(Poolしておき)、要求に応じてその確保済みコネクションから貸し出すのです。
あるいはデータベースへの実際の接続は要求時に行うとしても、切断の要求があっても実際の切断は行わないようにします。そのまま確保しておき(Poolしておき)、別の接続要求があったときに確保済みコネクションがあればそこから貸し出すのです。
DBCPの場合でもコネクションを取得するクラスではgetConnectionメソッドにより取得しますが、この意味合いが非DBCPの場合と異なります。
非DBCPの場合はgetConnectionはデータベースへの接続、コネクションのCloseはデータベースからの切断を意味します。
これに対してDBCPの場合はgetConnectionはコネクションを借り受ける、コネクションのCloseはコネクションを返却する、という意味になります。
JDBCによるデータベースアクセスで、DBCPを使う場合の手順を説明すると次のようになります。
-
InitialContextを生成
-
InitialContext.lookup(データソース名)で確保済みコネクションプールのデータソースを取得
-
データソース.getConnection()で確保済みコネクションプールからコネクション(Connection):接続を取得(借り受ける)
-
取得したコネクション:接続からStatementを生成し、SQL文を設定して実行
-
処理終了後にStatementをClose
-
続いてコネクション(Connection):接続をCloseしてコネクションプールに返却
手順の中には、個別にコネクションを確保する場合と比べると、接続先データベース、接続ユーザーID、 接続パスワードの指定がありません。これらは事前にAPサーバー上に、データソースとして設定しておきます。Javaプログラム側からはどのデータソースを使うかを指定することによって、接続先データベースが決まります。
・TOMCAT5.5、TOMCAT4.1のとき
The Apache Software FoundationのJakartaプロジェクトで公開されている、Commons DBCPを使います。これはhttp://commons.apache.org/downloads/download_dbcp.cgiにあります。
このページのBinaryから1.2.2.zipのリンクを選択し(2009/8/11時点)、ダウンロードしてください。ダウンロードしたファイルはcommons-dbcp-1.2.2.zipという名前です。
このダウンロードした圧縮ファイル内にあるcommons-dbcp-1.2.2.jarファイルを、TOMCATインストールディレクトリのcommon\libにコピーし、ファイル名をtomcat-dbcp.jarに変更します。
・TOMCAT6.0のとき
TOMCAT6系列の場合はTOMCATインストールディレクトリ\libに、あらかじめtomcat-dbcp.jarファイルが含まれています。そのため別途Jakartaプロジェクトからダウンロードする必要はありません。
ここでは「アプリ毎の環境設定」の説明に合わせます。そのためDBCPリソースを定義するコンテキストの設定ファイルは、TOMCATインストールディレクトリ\conf\Catalina\localhostの下にあるTestAp.xmlを対象にします。
DBCP用に追加するのは太字のResourceに関する設定内容です。ここで接続先データベースや接続ユーザーID、接続パスワードといった、データソースのリソースを定義しておきます。
コンテキスト設定ファイルのリソース定義例
<?xml version="1.0" encoding="Windows-31J"?>
<Context crossContext="true" docBase="TestAp" path="/TestAp" reloadable="true"
workDir="work\Catalina\localhost\TestAp">
<Valve className="org.apache.catalina.valves.AccessLogValve"
prefix="localhost_TestAp_log." suffix=".txt" pattern="common"/>
<Resource name="jdbc/TestApDS"
description="TestAp H2DB DBCP"
auth="Container"
type="javax.sql.DataSource"
username="DBユーザーID"
password="DBパスワード"
driverClassName="org.h2.Driver"
url="jdbc:h2:file:C:\work\data\testdb"
maxActive="20"
maxIdle="10"
maxWait="-1"
logAbandoned="true"
/>
</Context>
|
Resourceタグの設定内容
パラメータ |
説明 |
name | リソース名 |
このリソース定義に対して名前を付ける。ここで付けた名前で、web.xml内のリソース参照設定で参照する。
またJavaプログラム内で、データソースを取得するときもこの名前を使う。 |
description | 説明 |
このリソース定義の説明、コメントを指定する。 |
auth | 許可 |
ApplicationまたはContainerが指定可能。Containerを指定する。 |
type | リソースタイプ |
DBCP用のデータソース定義であることを指定する。javax.sql.DataSourceを指定する。 |
userid | DB接続ユーザーID |
対象データベースへの接続用ユーザーIDを指定する。 |
password | DB接続パスワード |
対象データベースへの接続用ユーザーID用パスワードを指定する。 |
driverClassName | JDBCドライバ |
対象データベース用のJDBCドライバを指定する。
この例ではH2 DB用のJDBCドライバを指定している。 |
url | 接続対象データベース |
接続対象データベース用を指定する。
この例ではH2 DBのデータベースに、組込モードで接続するように指定している(C:\work\dataにあるtestdbという名前のデータベースに、組込モードで接続している)。 |
maxActive | 最大接続数 |
保持可能な最大接続数(コネクション数)を指定する。ここで指定した数になるまで、新たな接続要求を受け付ける。同時接続数がこの数に達した場合、新たにデータベースに接続はせず、接続要求を出した側は待ちになる。
ここにマイナス値を指定した場合は、最大接続数に上限を設けないことを意味する。 |
maxIdle | 最大接続保持数 |
コネクションプールがアイドル状態(接続要求が一つもない状態)になったときに、保持し続ける最大接続数(コネクション数)を指定する。
ここにマイナス値を指定した場合は、最大接続保持数に上限を設けないことを意味する。 |
maxWait | 接続保持待機時間 |
確保したコネクションが未使用状態になった時、ここでミリ秒単位で指定した時間が経過すると、コネクションプールからデータベースへの該当コネクションを切断する。
ここに−1を指定した場合は、未使用になったコネクションについても切断せずに保持し続けることを意味する。 |
接続対象データベースがH2 DBで、それに組込モードで接続設定するときに注意点があります。「H2 DB インストール・設定メモ」の「データベースファイルの場所」や、特に「組込モード時のデータベースファイルの場所」で説明してある、接続先データベースのURL指定についてです。
H2 DBコンソールやOpenOffice BaseなどからJDBC経由で接続する際、"jdbc:h2:file:~testdbとすると、C:\Documents and Settings\Windowsユーザー名\、つまりユーザーHOMEディレクトリのtestdbデータベースに接続されました。
ところがTOMCAT下でDBCP経由で同じ指定をしても、接続先データベースの参照場所が異なります。この指定パターン、Resourceタグのurlパラメータで指定するときに"jdbc:h2:file:~testdbとすると、C:\直下のtestdbデータベースを参照します。
従ってTOMCAT下でDBCPを組込モードで接続する場合、必ずフルパス指定するようにしてください。
次は定義したDBCPリソースを、コンテキスト(アプリケーション毎の実行環境)側で参照するための設定方法を説明します。
ここでも「アプリ毎の環境設定」の説明に合わせます。そのためコンテキストの設定ファイルは、TOMCATインストールディレクトリ\webapps\TestAp\WEB-INF\の下にあるweb.xmlを対象にします。「アプリ毎の環境設定」で説明したサンプルのweb.xmlに、DBCPリソース参照の設定を追加することにします。web.xmlサンプルの、最後の部分にDBCPリソース参照を追加しました。
web.xmlのリソース参照設定例
<?xml version="1.0" encoding="Windows-31J"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/j2ee/dtds/web-app_2_3.dtd">
<web-app>
<!-- クライアントからのパラメータの文字エンコードをShift-JISにする -->
<filter>
<filter-name>Set Character Encoding</filter-name>
<filter-class>filters.SetCharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>Shift_JIS</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>Set Character Encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- デフォルトのサーブレット -->
<servlet>
<servlet-name>invoker</servlet-name>
<servlet-class>
org.apache.catalina.servlets.InvokerServlet
</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>0</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
<!-- デフォルトのJSPサーブレット -->
<servlet>
<servlet-name>jsp</servlet-name>
<servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
<init-param>
<param-name>fork</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>xpoweredBy</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>3</load-on-startup>
</servlet>
<!-- デフォルトのサーブレットマッピング -->
<servlet-mapping>
<servlet-name>invoker</servlet-name>
<url-pattern>/servlet/*</url-pattern>
</servlet-mapping>
<!-- デフォルトのJSPサーブレットマッピング -->
<servlet-mapping>
<servlet-name>jsp</servlet-name>
<url-pattern>*.jsp</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>jsp</servlet-name>
<url-pattern>*.jspx</url-pattern>
</servlet-mapping>
<!-- DBCPリソースの参照 -->
<resource-ref>
<description>TestAp DB Connection</description>
<res-ref-name>jdbc/TestApDS</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
</web-app>
|
resource-refタグの設定内容
パラメータ |
説明 |
description | 説明 |
このリソース参照定義の説明、コメントを指定する。 |
res-ref-name | 参照リソース名 |
参照する、コンテキスト設定ファイル(ここの例ではTestAp.xml)のリソース定義名を指定する。
Javaプログラム内で、データソースを取得するときはこの名前を使う。 |
res-type | 参照リソースタイプ |
参照しているリソースが、DBCP用のデータソース定義であることを指定する。javax.sql.DataSourceを指定する。 |
res-auth | 許可 |
ApplicationまたはContainerが指定可能。Containerを指定する。 |
続いてこれまでの設定例に基づいたコネクションプールを使用して、そこからコネクションを取得するまでのJavaサンプルを例示します。
DBCPデータソースからのConnection取得のJava例
import java.sql.Connection;
import java.sql.SQLException;
import javax.naming.InitialContext;
import javax.sql.DataSource;
import javax.naming.NamingException;
public Connection get_connection() throws NamingException, SQLException
{
private static final String TESTAP_DS = "java:/comp/env/jdbc/TestApDS";
InitialContext w_ctx = null; // コンテキスト
DataSource w_ds = null; // データソース
Connection w_con = null; // コネクション
w_ctx = new InitialContext();
w_ds = (DataSource) w_ctx.lookup(TESTAP_DS); // JNDIによりデータソースの取得
w_con = w_ds.getConnection(); // 接続プールよりコネクションを取得
w_con.setAutoCommit(false); // オートコミットOFF
return w_con;
}
|
get_connectionメソッドの最初に定義している定数TESTAP_DSの値、"java:/comp/env/jdbc/TestDB"ですが、これはリソース定義で設定したものを指定します。
前半の"java:/comp/env/"は、決まりものです。
後半の"jdbc/TestDB"が、リソース参照定義のres-ref-nameタグで指定した名前を選択しています。この定数TESTAP_DSの内容でInitialContextからlookupすることにより、データソースのリソースを取得します。
ここで取得したデータソースリソースは、コネクションプールを指しています。このコネクションプールからgetConnectionによりコネクションを取得します。
これでJavaプログラムからのデータソースlookup→web.xmlのリソース参照定義→コンテキスト設定ファイル(TestAp.xml)のリソース定義→データソース定義で指定した接続先データベース、と繋がるわけです。
一連の処理終了後は、コネクションプールを使わずにDriverManager.getConnectionで取得したコネクションの場合と同じように、コネクションをCloseします。
|