2009-8-20作成

 ■TOMCAT コネクションプール(DBCP)の利用

 ここではTOMCAT上で稼働するJavaプログラムからデータベースを操作するとき、データベースとの接続にコネクションプール:DBCP(DataBase Connection Pool)という仕組みを使う方法について説明します。

 ■データベースアクセスの手順

 Javaプログラムからデータベースにアクセスする場合で、JDBCを使った例で手順を説明すると次のようになります。

  1. Class.forName(対象JDBCドライバ)でJDBCドライバをロード
  2. DriverManager.getConnection(接続先DB, 接続ユーザーID, 接続パスワード)でDBに接続し、コネクション(Connection):接続を取得
  3. 取得したコネクション:接続からStatementを生成し、SQL文を設定して実行
  4. 処理終了後にStatementをClose
  5. 続いてコネクション(Connection):接続をCloseしてDBから切断

 この中でパフォーマンス面で問題になり得るのが2と5、データベースへの接続と切断です。

 例えばあるクライアント画面からのリクエストで結果表示画面を作成するのに、6個のテーブルアクセスが必要だとします。

 テーブルやビュー単位にクラスを分けていることを想定すると、この結果表示画面作成に複数のデータベースアクセスクラスが実行されます。個々のクラス内で別個にデータベース接続・切断を実装しているとすると、処理単位の細かい接続・切断処理が複数実行されてしまいます。

 さらに複数クライアントからの同時処理を考えると、この接続・切断処理がかなりの頻度発生します。そしてこのデータベース接続・切断処理はそこそこオーバーヘッドが掛かるので(とくにAPサーバーとDBサーバーが別サーバーのとき)、あまり頻度が高いとパフォーマンス上馬鹿になりません。

 ■DBCPとは

 一つの解決策としては個々のクラスで個別にデータベース接続・切断を行うのではなく、業務処理コントロールを担当するクラスで行う方法です。そして業務処理コントロールクラスからデータベースアクセスクラスを呼び出すときに、引数としてコネクション:接続を渡します。

 こうすることによって一つのコネクション:接続を、複数クラス間で使いまわすのです。

 別の方法がDBCP(DataBase Connection Pool)を使う方法です。これはデータベースへのコネクションを個々のクラスで個別に取得するのではなく、あらかじめ確保済みのコネクション(Pooled Connection)を使いまわす方法です。

 ■DBCPの仕組み

 DBCPを使う場合はデータベースコネクションの管理は、J2EE実行環境であるAPサーバーが行うように設定します。複数(設定内容による)のコネクション:接続を最初にまとめて確保しておき(Poolしておき)、要求に応じてその確保済みコネクションから貸し出すのです。

 あるいはデータベースへの実際の接続は要求時に行うとしても、切断の要求があっても実際の切断は行わないようにします。そのまま確保しておき(Poolしておき)、別の接続要求があったときに確保済みコネクションがあればそこから貸し出すのです。

 DBCPの場合でもコネクションを取得するクラスではgetConnectionメソッドにより取得しますが、この意味合いが非DBCPの場合と異なります。

 非DBCPの場合はgetConnectionはデータベースへの接続、コネクションのCloseはデータベースからの切断を意味します。

 これに対してDBCPの場合はgetConnectionはコネクションを借り受ける、コネクションのCloseはコネクションを返却する、という意味になります。

 ■データベースアクセスの手順(DBCP)

 JDBCによるデータベースアクセスで、DBCPを使う場合の手順を説明すると次のようになります。

  1. InitialContextを生成
  2. InitialContext.lookup(データソース名)で確保済みコネクションプールのデータソースを取得
  3. データソース.getConnection()で確保済みコネクションプールからコネクション(Connection):接続を取得(借り受ける)
  4. 取得したコネクション:接続からStatementを生成し、SQL文を設定して実行
  5. 処理終了後にStatementをClose
  6. 続いてコネクション(Connection):接続をCloseしてコネクションプールに返却

 手順の中には、個別にコネクションを確保する場合と比べると、接続先データベース、接続ユーザーID、 接続パスワードの指定がありません。これらは事前にAPサーバー上に、データソースとして設定しておきます。Javaプログラム側からはどのデータソースを使うかを指定することによって、接続先データベースが決まります。

 ■設定方法

 ◇DBCPドライバ

 ・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リソース定義

 ここでは「アプリ毎の環境設定」の説明に合わせます。そのため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を指定する。
useridDB接続ユーザーID  対象データベースへの接続用ユーザーIDを指定する。
passwordDB接続パスワード  対象データベースへの接続用ユーザーID用パスワードを指定する。
driverClassNameJDBCドライバ  対象データベース用の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リソース参照定義

 次は定義した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を指定する。

 ◇CONNECTION取得のJavaサンプル

 続いてこれまでの設定例に基づいたコネクションプールを使用して、そこからコネクションを取得するまでの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します。




このページの先頭  サーバーJava入門先頭  TOMCAT編先頭
Copyright © 2009- YOK. All Rights Reserved.