5.9. 接続プールとデータソース

5.9.1. JDBC、JDK バージョンサポート

JDBC 2 付属の API に、標準の接続プール機能が導入されました。このアドオン API は JDBC 2.0 オプションパッケージまたは JDBC 2.0 標準拡張と呼ばれます。以来、これらの機能はコア JDBC 3 API に含まれています。PostgreSQL JDBC ドライバは、JDK 1.3.x とともに動作する JDBC 2.0 オプションパッケージ (JDBC 2) または JDK 1.4+ (JDBC 3) でこれらの機能をサポートしています。JDBC 2.0 オプションパッケージはほとんどのアプリケーションサーバに組み込まれていますが、Sun の JDBC ダウンロードサイト から個別に入手することも可能です。

5.9.2. JDBC 接続プール API

JDBC API には、接続プール用のクライアントインタフェースおよびサーバインタフェースが用意されています。クライアントインタフェースは javax.sql.DataSource です。これは通常、アプリケーションコードがプールされたデータベース接続を取得するために使用します。サーバインタフェースは javax.sql.ConnectionPoolDataSource で、ほとんどのアプリケーションサーバはこれを使用して PostgreSQL JDBC とのインタフェースをとります。

アプリケーションサーバ環境では、アプリケーションサーバ構成は通常 PostgreSQL ConnectionPoolDataSource の実装を参照し、アプリケーションコンポーネントコードは通常、アプリケーションサーバ (PostgreSQL ではなく) が提供する DataSource 実装を獲得します。

アプリケーションサーバを使用しない環境では、PostgreSQL は、アプリケーションが直接使用できる DataSource を 2 つ実装しています。1 つの実装が接続プールを実行し、もう 1 つの実装はプールは行わずに DataSource インタフェースを介して単にデータベース接続へのアクセスを提供します。 繰り返しますが、これらの実装は、アプリケーションサーバが ConnectionPoolDataSource インタフェースをサポートしていない場合を除き、アプリケーションサーバ環境で使用すべきではありません 。

5.9.3. アプリケーションサーバ: ConnectionPoolDataSource

PostgreSQL は、JDBC 2 用と JDBC 3 用に ConnectionPoolDataSource をそれぞれ 1 つずつ実装しています。

Table 5-1. ConnectionPoolDataSource 実装

JDBC実装クラス
2org.postgresql.jdbc2.optional.ConnectionPool
3org.postgresql.jdbc3.Jdbc3ConnectionPool

どちらの実装も同じ構成スキーマを使用しています。JDBC では ConnectionPoolDataSource を JavaBean プロパティを使用して構成する必要があります。 したがってこれらのプロパティのそれぞれに get メソッドと set メソッドができます。

Table 5-2. ConnectionPoolDataSource 構成プロパティ

プロパティ説明
serverNameStringPostgreSQL データベースサーバのホスト名
databaseNameStringPostgreSQL データベース名
portNumberintPostgreSQL データベースサーバが監視している TCP/IP ポート (デフォルトのポートを使用する場合は 0)
userStringデータベース接続の作成に使用するユーザ
passwordStringデータベース接続の作成に使用するパスワード
defaultAutoCommitboolean接続が呼び出し元に渡される際に autoCommit (自動コミット) を有効にするか無効にするかを指定。デフォルトは自動コミットを無効にする false です。

多くのアプリケーションサーバは、プロパティ形式の構文を使用してこれらのプロパティを構成するので、プロパティをテキストのブロックとして入力することはめずらしくありません。

Example 5-5. ConnectionPoolDataSource 構成の例

アプリケーションサーバで、すべてのプロパティを 1 つの領域に入力する場合は、次のようにすることができます。

serverName=localhost
databaseName=test
user=testuser
password=testpassword

あるいは、改行をする代わりに以下のようにセミコロンで区切ることもできます。

serverName=localhost;databaseName=test;user=testuser;password=testpassword

5.9.4. アプリケーション: DataSource

PostgreSQL は、JDBC 2 用と JDBC 3 用に DataSource をそれぞれ 2 つずつ実装しています。 クライアントが close メソッドを呼び出すと、プールの実装は実際に接続をクローズするのではなく、その接続を使用可能な接続のプールに返して他のクライアントが使用できるようにします。これにより、接続を何度もオープンしクローズすることによるオーバーヘッドをなくすとともに、多数のクライアントが少数のデータベース接続を共有することが可能になります。

このプールデータソース実装は、必ずしも優れた機能を持っているとは言えません。例えば、接続はプール自体がクローズされるまでは決してクローズされないので、プールを縮小することができません。また、デフォルトで構成されたユーザ以外のユーザによって要求された接続はプールされません。多くのアプリケーションサーバではより高度なプール機能を提供しており、代わりに ConnectionPoolDataSource 実装を使用しています。

Table 5-3. DataSource 実装

JDBCプール実装クラス
2なしorg.postgresql.jdbc2.optional.SimpleDataSource
2ありorg.postgresql.jdbc2.optional.PoolingDataSource
3なしorg.postgresql.jdbc3.Jdbc3SimpleDataSource
3ありorg.postgresql.jdbc3.Jdbc3PoolingDataSource

すべての実装で同じ構成スキーマを使用しています。JDBC では DataSource を JavaBean プロパティを使用して構成する必要があります。したがってこれらのプロパティのそれぞれに get メソッドと set メソッドができます。

Table 5-4. DataSource 構成プロパティ

プロパティ説明
serverNameStringPostgreSQL データベースサーバのホスト名
databaseNameStringPostgreSQL データベース名
portNumberintPostgreSQL データベースサーバが監視している TCP/IP ポート (デフォルトのポートを使用する場合は 0)
userStringデータベース接続の作成に使用するユーザ
passwordStringデータベース接続の作成に使用するパスワード

このプール実装に構成プロパティをいくつか追加する必要があります。

Table 5-5. 追加のプール DataSource 構成プロパティ

プロパティ説明
dataSourceNameStringプール DataSource はすべて固有の名前を持つ必要があります
initialConnectionsintプールの開始時に作成されるデータベース接続数
maxConnectionsint一度にオープンできるデータベース接続の最大数。これより多くの接続が要求されると、接続がプールに返されるまで呼び出し側がハングします。

プール DataSource を使用する典型的なアプリケーションコードの例を示します。

Example 5-6. DataSource コード例

プール DataSource を開始するコードの例

Jdbc3PoolingDataSource source = new Jdbc3PoolingDataSource();
source.setDataSourceName("A Data Source");
source.setServerName("localhost");
source.setDatabaseName("test");
source.setUser("testuser");
source.setPassword("testpassword");
source.setMaxConnections(10);

プールに入っている接続を使用するためのコードの例を以下に示します。接続を閉じた状態にしておくことが重要です。開いているとプールは接続をリークし、最終的にすべてのクライアントをロックアウトします。

Connection con = null;
try {
    con = source.getConnection();
    // 接続を使用する
} catch(SQLException e) {
    // エラーをログに記録
} finally {
    if(con != null) {
        try {con.close();}catch(SQLException e) {}
    }
}

5.9.5. DataSource と JNDI

ConnectionPoolDataSource および DataSource の実装はすべて、JNDI に格納することができます。.非プール実装の場合、JNDI からオブジェクトが抽出される度に、格納済みのインスタンスと同じ設定の新しいインスタンスが作成されます。プール実装については、同じインスタンスが使用可能であればそのインスタンスが抽出され (異なる JVMJNDI からプールを抽出するのではなく) 、使用可能でない場合は、同じ設定で新しいインスタンスが作成されます。

アプリケーションサーバ環境では、アプリケーションサーバの DataSource インスタンスは通常 PostgreSQL ConnectionPoolDataSource 実装ではなく、JNDI に格納されます。

アプリケーション環境では、アプリケーションは JNDIDataSource を格納する場合があります。こうすることにより、アプリケーションは、DataSource への参照をこれを使用するすべてのアプリケーションコンポーネントに対して使用可能にする必要がなくなります。

Example 5-7. DataSource JNDI コード例

プール DataSource を初期化して JNDI に追加するアプリケーションコードの例を以下に示します。

Jdbc3PoolingDataSource source = new Jdbc3PoolingDataSource();
source.setDataSourceName("A Data Source");
source.setServerName("localhost");
source.setDatabaseName("test");
source.setUser("testuser");
source.setPassword("testpassword");
source.setMaxConnections(10);
new InitialContext().rebind("DataSource", source);

プールに入っている接続を使用するためのコードの例を以下に示します。

Connection con = null;
try {
    DataSource source = (DataSource)new InitialContext().lookup("DataSource");
    con = source.getConnection();
    // 接続を使用する
} catch(SQLException e) {
    // エラーをログに記録
} catch(NamingException e) {
    // DataSource wasn't found in JNDI
} finally {
    if(con != null) {
        try {con.close();}catch(SQLException e) {}
    }
}

5.9.6. アプリケーションサーバ構成の具体例

特定のアプリケーションサーバの構成例を示します。