6.2. JDBC データソースの概要
JDBC 1.4 標準では、java.sql.Connection
オブジェクトの ファクトリー として機能する javax.sql.DataSource
インターフェイスが導入されました。通常、このようなデータソースは JNDI レジストリーにバインドされ、サーブレットや EJB などの JavaEE コンポーネント内に配置または挿入されていました。重要な側面は、これらのデータソースが アプリケーションサーバー 内で 設定 され、デプロイされたアプリケーションで名前で 参照 されていることです。
以下の 接続 オブジェクトには独自の データソース があります。
データソース | 接続 |
---|---|
|
|
|
|
|
|
上記の各 データソース で最も重要な相違点は以下のとおりです。
最も重要なのは、
javax.sql.DataSource
は、java.sql.Connection
インスタンスを取得するための ファクトリーのようなオブジェクトである点です。ほとんどのjavax.sql.DataSource
実装が通常接続プーリングを実行することが事実であり、イメージを変更すべきではありません。これは、アプリケーションコードで使用する必要がある唯一のインターフェイスです。実装しているのはどれかは重要ではありません。- 直接 JDBC アクセス
-
JPA 永続ユニット設定 (
<jta-data-source>
または<non-jta-data-source>
) - Apache Camel や Spring Framework などの一般的なライブラリー
最も重要なのは、
javax.sql.ConnectionPoolDataSource
は汎用 (データベース固有でない) 接続プール/データソースとデータベース固有のデータソースとの間の ブリッジ であることです。SPI インターフェイスとして処理できます。通常、アプリケーションコードは、JNDI から取得され、アプリケーションサーバーによって実装される汎用javax.sql.DataSource
オブジェクトに対応します (おそらくcommons-dbcp2
などのライブラリーを使用します)。一方、アプリケーションコードはjavax.sql.ConnectionPoolDataSource
と直接インターフェイスしません。これは、アプリケーションサーバーとデータベース固有のドライバーの間で使用されます。以下のシーケンス図は、これを示しています。
javax.sql.XADataSource
は、javax.sql.XAConnection
とjavax.transaction.xa.XAResource
を取得する方法です。javax.sql.ConnectionPoolDataSource
と同じで、これはアプリケーションサーバーとデータベース固有のドライバーとの間で使用されます。これは、今回は JTA トランザクションマネージャーなど、異なるアクターが含まれる図を若干変更しています。
上記の 2 つの図に示すように、アプリケーションサーバーと対話できます。これは一般的なエンティティーで、 javax.sql.DataSource
および javax.transaction.UserTransaction
インスタンスを設定できます。このようなインスタンスには、JNDI を使用するか、CDI や他の依存関係メカニズムを使用して注入することでアクセスできます。
重要な点は、アプリケーションが XA トランザクションや接続プーリングを使用する場合でも、アプリケーションは他の 2 つの JDBC データソースインターフェイスではなく、javax.sql.DataSource
と対話することです。
6.2.1. データベース固有のデータソースおよび汎用データソース
JDBC データソースの実装は 2 つのカテゴリーに分類されます。
以下のような汎用の
javax.sql.DataSource
実装:- Apache Commons DBCP(2)
- Apache Tomcat JDBC(DBCP ベース)
-
javax.sql.DataSource
、javax.sql.XADataSource
、およびjavax.sql.ConnectionPoolDataSource
のデータベース固有の実装
汎用 javax.sql.DataSource
実装によって独自のデータベース固有の接続を作成できないことが紛らわしい可能性があります。汎用 データソースが java.sql.Driver.connect()
または java.sql.DriverManager.getConnection()
を使用できたとしても、データベース固有の javax.sql.DataSource
実装でこの 汎用 データソースを設定するのが通常、適切またはクリーンです。
汎用 データソースが JTA と対話する場合は、javax.sql.XADataSource
のデータベース固有の実装で設定する 必要 があります。
イメージを閉じるには、通常、汎用 データソースは、接続プーリングを実行するために javax.sql.ConnectionPoolDataSource
のデータベース固有の実装を必要としません。既存のプールは通常、標準の JDBC インターフェイス (javax.sql.ConnectionPoolDataSource
および javax.sql.PooledConnection
) なしでプーリングを処理し、代わりに独自のカスタム実装を使用します。
6.2.2. 一部の汎用データソース
サンプルのよく知られた汎用データソースである ApacheCommonsDBCP(2) を見ていきます。
javax.sql.XADataSource 実装
DBCP2 には、javax.sql.XADataSource
の実装は含まれていないことが予想されます。
javax.sql.ConnectionPoolDataSource implementations
DBCP2 には javax.sql.ConnectionPoolDataSource
: org.apache.commons.dbcp2.cpdsadapter.DriverAdapterCPDS
の実装が含まれます。java.sql.DriverManager.getConnection()
を呼び出して javax.sql.PooledConnection
オブジェクトを作成します。このプールを直接使用することはできず、以下のドライバーの アダプター として扱う必要があります。
-
独自の
javax.sql.ConnectionPoolDataSource
実装は指定しないでください。 - 接続プールに関する JDBC の推奨事項 に応じて使用する必要があります。
上記のシーケンス図に示すように、ドライバーは javax.sql.ConnectionPoolDataSource
を直接提供するか、org.apache.commons.dbcp2.cpdsadapter.DriverAdapterCPDS
アダプター の助けを借りて提供します。一方、DBCP2 は、以下のいずれかで アプリケーションサーバー コントラクトを以下のいずれかで実装します。
-
org.apache.commons.dbcp2.datasources.PerUserPoolDataSource
-
org.apache.commons.dbcp2.datasources.SharedPoolDataSource
これらのプールは、設定段階で javax.sql.ConnectionPoolDataSource
のインスタンスを取ります。
これは DBCP2 の最も重要で興味深い部分です。
javax.sql.DataSource implementations
接続プール機能を実装するには、JDBC の推奨事項 に従って、javax.sql.ConnectionPoolDataSource
javax.sql.PooledConnection
SPI を使用する必要はありません。
以下は、DBCP2 の 通常 のデータソースの一覧です。
-
org.apache.commons.dbcp2.BasicDataSource
-
org.apache.commons.dbcp2.managed.BasicManagedDataSource
-
org.apache.commons.dbcp2.PoolingDataSource
-
org.apache.commons.dbcp2.managed.ManagedDataSource
2 つの 軸 があります。
基本 vs プーリング
この軸は、プーリング設定の要素を決定します。
いずれの種類のデータソースも、java.sql.Connection
オブジェクトの プーリング を実行します。唯一 の違いは、以下の点です。
-
基本的な データソースは、
org.apache.commons.pool2.impl.GenericObjectPool
の内部インスタンスを設定するために使用されるmaxTotal
またはminIdle
などの Bean プロパティーを使用して設定されます。 -
プーリング データソースは、外部作成/設定された
org.apache.commons.pool2.ObjectPool
で設定されます。
managed vs non-managed
この軸は、接続作成の要素と JTA の動作を決定します。
管理対象外の基本的な データソースは、
java.sql.Driver.connect()
を内部で使用することで、java.sql.Connection
インスタンスを作成します。管理対象外のプーリング データソースは、渡された
org.apache.commons.pool2.ObjectPool
オブジェクトを使用してjava.sql.Connection
インスタンスを作成します。管理対象のプーリングデータソースは、
org.apache.commons.dbcp2.managed.ManagedConnection
オブジェクト内でjava.sql.Connection
インスタンスをラップし、JTA コンテキストで必要に応じてjavax.transaction.Transaction.enlistResource()
が呼び出されるようにします。ただし、ラップされる実際の接続は、プールが設定されたorg.apache.commons.pool2.ObjectPool
オブジェクトから取得されます。managed basic データソースは、専用の
org.apache.commons.pool2.ObjectPool
の設定を解放します。代わりに、既存の実際のデータベース固有のjavax.sql.XADataSource
オブジェクトを設定すれば十分です。Bean プロパティーは、org.apache.commons.pool2.impl.GenericObjectPool
の内部インスタンスを作成するために使用されます。これは、管理対象プーリングのデータソースの内部インスタンス (org.apache.commons.dbcp2.managed.ManagedDataSource
) に渡されます。
DBCP2 を実行できないのは XA トランザクションの回復 です。DBCP2 はアクティブな JTA トランザクションで XAResources を正しく登録しますが、リカバリーは実行されません。これは個別に行う必要があり、設定は、通常選択されたトランザクションマネージャーの実装 (Narayana など) に固有のものです。
6.2.3. 使用するパターン
推奨のパターンは以下のとおりです。
-
接続/XA 接続を作成できるデータベース固有の設定 (URL、クレデンシャルなど) で、データベース固有 の
javax.sql.DataSource
またはjavax.sql.XADataSource
インスタンスを作成または取得します。 -
データベース固有でない設定 (接続プーリング、トランザクションマネージャーなど) でデータベース固有でない
javax.sql.DataSource
インスタンス (上記のデータベース固有のデータソースで内部的設定された) を作成および取得します。 -
javax.sql.DataSource
を使用してjava.sql.Connection
のインスタンスを取得し、JDBC 操作を実行します。
以下は 正規 の例です。
// Database-specific, non-pooling, non-enlisting javax.sql.XADataSource PGXADataSource postgresql = new org.postgresql.xa.PGXADataSource(); // Database-specific configuration postgresql.setUrl("jdbc:postgresql://localhost:5432/reportdb"); postgresql.setUser("fuse"); postgresql.setPassword("fuse"); postgresql.setCurrentSchema("report"); postgresql.setConnectTimeout(5); // ... // Non database-specific, pooling, enlisting javax.sql.DataSource BasicManagedDataSource pool = new org.apache.commons.dbcp2.managed.BasicManagedDataSource(); // Delegate to database-specific XADatasource pool.setXaDataSourceInstance(postgresql); // Delegate to JTA transaction manager pool.setTransactionManager(transactionManager); // Non database-specific configuration pool.setMinIdle(3); pool.setMaxTotal(10); pool.setValidationQuery("select schema_name, schema_owner from information_schema.schemata"); // ... // JDBC code: javax.sql.DataSource applicationDataSource = pool; try (Connection c = applicationDataSource.getConnection()) { try (Statement st = c.createStatement()) { try (ResultSet rs = st.executeQuery("select ...")) { // ....
Fuse 環境では設定オプションが多くなり、DBCP2 を使用する必要はありません。