Tomcat JDBC コネクションプール

目次

はじめに

JDBC Connection Pool org.apache.tomcat.jdbc.pool は、Apache Commons DBCP コネクションプール の代替または置き換えとなるものです。

では、なぜ新しいコネクションプールが必要なのでしょうか?

理由をいくつかご紹介します

  1. Commons DBCP 1.x はシングルスレッドです。スレッドセーフであるためには、Commons はオブジェクトの割り当てと返却の両方において、短時間プール全体をロックします。これは Commons DBCP 2.x には当てはまりません。
  2. Commons DBCP 1.x は遅い場合があります。論理CPUの数が増え、オブジェクトを借りたり返したりしようとする同時実行スレッドの数が増加するにつれて、パフォーマンスが低下します。高並行システムでは、その影響は重大になる可能性があります。これは Commons DBCP 2.x には当てはまりません。
  3. Commons DBCP は60以上のクラスで構成されています。tomcat-jdbc-pool のコアは8クラスであり、将来の要件に対する変更ははるかに少ない変更で済みます。これだけでコネクションプール自体を実行でき、残りは付加的なものです。
  4. Commons DBCP は静的インターフェースを使用します。これは、特定のJREバージョンに対して適切なバージョンを使用しないと、NoSuchMethodException 例外が発生する可能性があることを意味します。
  5. コネクションプールがはるかにシンプルな実装で実現できるのに、60以上のクラスを書き直す価値はありません。
  6. Tomcat JDBC プールは、ライブラリ自体に追加のスレッドを追加することなく、接続を非同期で取得する機能を実装しています。
  7. Tomcat JDBC プールはTomcatモジュールであり、Tomcatで使用される簡素化されたロギングフレームワークであるTomcat JULIに依存しています。
  8. javax.sql.PooledConnection インターフェースを使用して、基盤となる接続を取得します。
  9. スタベーション耐性があります。プールが空でスレッドが接続を待っている場合、接続が返却されると、プールは待機中の正しいスレッドを起動します。ほとんどのプールは単にスタベーションに陥ります。

他のコネクションプール実装に追加された機能

  1. 高並行環境およびマルチコア/CPUシステムをサポートします。
  2. インターフェースの動的実装により、より低いバージョンのJDKでコンパイルされた場合でも、ランタイム環境のjava.sqlおよびjavax.sqlインターフェースをサポートします(JDBCドライバも同様である限り)。
  3. バリデーション間隔 - 接続を使用するたびにバリデーションを行う必要はなく、接続を借りたり返したりするときに行うことができますが、設定可能な間隔よりも頻繁に行うことはありません。
  4. 一度だけ実行されるクエリ - データベースへの接続が確立されたときに一度だけ実行される設定可能なクエリです。接続が確立されている間ずっと存在させたいセッション設定を行うのに非常に便利です。
  5. カスタムインターセプタを設定する機能。これにより、カスタムインターセプタを記述して機能を拡張できます。インターセプタを使用して、クエリ統計の収集、セッション状態のキャッシュ、障害発生時の接続の再接続、クエリの再試行、クエリ結果のキャッシュなどを行うことができます。選択肢は無限であり、インターセプタは動的で、java.sql/javax.sqlインターフェースのJDKバージョンに縛られません。
  6. 高パフォーマンス - パフォーマンスの違いについては後述します
  7. 非常にシンプル - 非常に簡素化された実装のため、行数とソースファイル数が非常に少なく、(最後に確認した時点では)200以上のソースファイルを持つc3p0と比較して、Tomcat JDBCのコアは8ファイルで、コネクションプール自体はその約半分です。バグが発生した場合でも、追跡が速く、修正が容易になります。複雑性の軽減は、当初から重点が置かれてきました。
  8. 非同期接続取得 - 接続要求をキューに入れ、Future<Connection> を受け取ることができます。
  9. より良いアイドル接続処理。接続を直接閉じる代わりに、引き続き接続をプールし、より賢いアルゴリズムでアイドルプールをサイジングできます。
  10. 接続が放棄されたとみなされるタイミングを決定できます。それはプールが満杯になったときか、またはプール使用しきい値を指定して直接タイムアウトしたときかです。
  11. ステートメント/クエリのアクティビティが発生すると、放棄接続タイマーはリセットされます。これにより、長期間使用されている接続がタイムアウトしないようにします。これはResetAbandonedTimer を使用して実現されます。
  12. 一定時間接続された後、接続を閉じます。プールに戻ったときに、経過時間に基づいて閉じます。
  13. 接続が放棄された疑いがある場合にJMX通知とログエントリを取得します。これはremoveAbandonedTimeoutに似ていますが、アクションは実行せず、情報のみを報告します。これはsuspectTimeout属性を使用して実現されます。
  14. 接続はjava.sql.Driverjavax.sql.DataSourceまたはjavax.sql.XADataSourceから取得できます。これはdataSourceおよびdataSourceJNDI属性を使用して実現されます。
  15. XA接続サポート

使用方法

Tomcat コネクションプールの使用は可能な限りシンプルになるように設計されており、commons-dbcp に慣れている方にとっては非常に簡単な移行となるでしょう。他のコネクションプールからの移行も、かなり簡単です。

追加機能

Tomcat コネクションプールは、他のほとんどのプールが提供する機能に加えて、いくつかの追加機能を提供します。

  • initSQL - 接続が作成されたときに、SQLステートメントを正確に一度だけ実行する機能
  • validationInterval - 接続に対する検証を実行することに加えて、頻繁に実行しすぎないようにします。
  • jdbcInterceptors - プール、クエリ実行、結果セット処理に関してあらゆるカスタマイズを作成できる、柔軟でプラグイン可能なインターセプターです。これについては、詳細セクションで詳しく説明します。
  • fairQueue - スレッドの公平性を実現したり、非同期接続取得を使用したりするために、fairフラグをtrueに設定します。

Apache Tomcatコンテナ内

Tomcat コネクションプールは、Tomcat JDBCドキュメントで説明されているリソースとして設定されます。唯一の違いは、factory属性を指定し、その値をorg.apache.tomcat.jdbc.pool.DataSourceFactoryに設定する必要があることです。

スタンドアロン

コネクションプールには、もう一つ依存関係があり、それは tomcat-juli.jar です。スタンドアロンプロジェクトでbeanのインスタンス化を使用してプールを設定する場合、インスタンス化するbeanはorg.apache.tomcat.jdbc.pool.DataSourceです。JNDIリソースとしてコネクションプールを設定する際に使用するのと同じ属性(以下に文書化されています)が、データソースをbeanとして設定するために使用されます。

JMX

コネクションプールオブジェクトは、登録可能なMBeanを公開します。コネクションプールオブジェクトがMBeanを作成するには、jmxEnabledフラグをtrueに設定する必要があります。これは、プールがMBeanサーバーに登録されることを意味するものではなく、単にMBeanが作成されることを意味します。Tomcatのようなコンテナでは、Tomcat自体がDataSourceをMBeanサーバーに登録し、org.apache.tomcat.jdbc.pool.DataSourceオブジェクトが実際のコネクションプールMBeanを登録します。コンテナの外部で実行している場合は、指定した任意のオブジェクト名でDataSource自体を登録でき、それが基盤となるプールへの登録を伝播します。これを行うには、mBeanServer.registerMBean(dataSource.getPool().getJmxPool(),objectname)を呼び出します。この呼び出しの前に、dataSource.createPool()を呼び出してプールが作成されていることを確認してください。

属性

commons-dbcp と tomcat-jdbc-pool の切り替えを非常に簡単にするため、ほとんどの属性は同じであり、同じ意味を持ちます。

JNDIファクトリとタイプ

属性説明
factory

factory は必須であり、その値は org.apache.tomcat.jdbc.pool.DataSourceFactory である必要があります。

type

Typeは常にjavax.sql.DataSourceまたはjavax.sql.XADataSourceである必要があります。

型に応じて、org.apache.tomcat.jdbc.pool.DataSourceまたはorg.apache.tomcat.jdbc.pool.XADataSourceが作成されます。

システムプロパティ

システムプロパティはJVM全体に適用され、JVM内で作成されたすべてのプールに影響します。

属性説明
org.apache.tomcat.jdbc.pool.onlyAttemptCurrentClassLoader

(boolean) JDBCドライバ、インターセプタ、バリデータなどの動的クラスのクラスローディングを制御します。false(デフォルト値)に設定すると、プールはまず現在のローダー(つまり、プールクラスをロードしたクラスローダー)を使用してロードを試み、クラスローディングが失敗した場合はスレッドコンテキストローダーを使用してロードを試みます。Apache Tomcat 8.0.8 以前との下位互換性を維持し、現在のローダーのみを試行したい場合は、この値をtrueに設定してください。設定されていない場合、デフォルト値はfalseです。

共通属性

これらの属性は commons-dbcp と tomcat-jdbc-pool で共有されますが、場合によってはデフォルト値が異なります。

属性説明
defaultAutoCommit

(boolean) このプールによって作成される接続のデフォルトの自動コミット状態。設定されていない場合、デフォルトはJDBCドライバのデフォルトです(設定されていない場合、setAutoCommitメソッドは呼び出されません)。

defaultReadOnly

(boolean) このプールによって作成される接続のデフォルトの読み取り専用状態。設定されていない場合、setReadOnlyメソッドは呼び出されません。(一部のドライバは読み取り専用モードをサポートしていません。例:Informix)

defaultTransactionIsolation

(String) このプールによって作成される接続のデフォルトのトランザクション分離状態。以下のいずれかです。(javadocを参照)

  • NONE
  • READ_COMMITTED
  • READ_UNCOMMITTED
  • REPEATABLE_READ
  • SERIALIZABLE

設定されていない場合、このメソッドは呼び出されず、JDBCドライバのデフォルトが使用されます。

defaultCatalog

(String) このプールによって作成される接続のデフォルトカタログ。

driverClassName

(String) 使用するJDBCドライバの完全修飾Javaクラス名。ドライバはtomcat-jdbc.jarと同じクラスローダーからアクセス可能である必要があります。

username

(String) 接続を確立するためにJDBCドライバに渡される接続ユーザー名。デフォルトでは、DataSource.getConnection(username,password)メソッドはメソッドに渡された資格情報を使用せず、ここで設定されたものを使用します。詳細については、alternateUsernameAllowedプロパティを参照してください。

password

(String) 接続を確立するためにJDBCドライバに渡される接続パスワード。デフォルトでは、DataSource.getConnection(username,password)メソッドはメソッドに渡された資格情報を使用せず、ここで設定されたものを使用します。詳細については、alternateUsernameAllowedプロパティを参照してください。

maxActive

(int) このプールから同時に割り当てることができるアクティブ接続の最大数。デフォルト値は 100 です。

maxIdle

(int) プール内に常に保持されるべき接続の最大数。デフォルト値はmaxActive:100です。アイドル接続は定期的にチェックされ(有効な場合)、minEvictableIdleTimeMillisよりも長くアイドル状態であった接続は解放されます。(testWhileIdleも参照)

minIdle

(int) プール内に常に保持されるべき確立された接続の最小数。バリデーションクエリが失敗した場合、コネクションプールはこの数を下回ることがあります。デフォルト値はinitialSize:10から派生します。(testWhileIdleも参照)

initialSize

(int) プールが起動したときに作成される初期接続数。デフォルト値は10です。

maxWait

(int) 利用可能な接続がない場合、例外をスローする前に、プールが接続が返却されるのを待つ最大ミリ秒数。デフォルト値は30000(30秒)です。

testOnBorrow

(boolean) プールからオブジェクトを借りる前に、そのオブジェクトが検証されるかどうかを示すフラグです。オブジェクトの検証に失敗した場合、そのオブジェクトはプールから削除され、別のオブジェクトを借りようとします。より効率的な検証を行うには、validationIntervalを参照してください。デフォルト値はfalseです。

testOnConnect

(boolean) 接続が最初に作成されるときにオブジェクトが検証されるかどうかを示すフラグ。オブジェクトの検証に失敗した場合、SQLExceptionをスローします。デフォルト値はfalseです。

testOnReturn

(boolean) プールに返却する前にオブジェクトが検証されるかどうかを示すフラグ。デフォルト値はfalseです。

testWhileIdle

(boolean) アイドルオブジェクトのエビクター(存在する場合)によってオブジェクトが検証されるかどうかを示すフラグ。オブジェクトの検証に失敗した場合、プールから削除されます。デフォルト値はfalseであり、プールのクリーナー/テストスレッドが実行されるためにはこのプロパティを設定する必要があります(timeBetweenEvictionRunsMillisも参照)。

validationQuery

(String) このプールから接続を呼び出し元に返す前に、接続を検証するために使用されるSQLクエリ。指定された場合、このクエリはデータを返す必要はなく、単にSQLExceptionをスローしてはいけません。デフォルト値はnullです。指定されていない場合、接続はisValid()メソッドによって検証されます。例としては、SELECT 1(mysql)、select 1 from dual(oracle)、SELECT 1(MS Sql Server)があります。

validationQueryTimeout

(int) 接続検証クエリが失敗するまでのタイムアウト秒数。これは、validationQueryを実行するステートメントに対してjava.sql.Statement.setQueryTimeout(seconds)を呼び出すことで機能します。プール自体はクエリをタイムアウトさせず、クエリのタイムアウトを強制するのは依然としてJDBCドライバ次第です。0以下の値は、この機能を無効にします。デフォルト値は-1です。

validatorClassName

(String) org.apache.tomcat.jdbc.pool.Validatorインターフェースを実装し、引数なしのコンストラクタ(暗黙的でも可)を提供するクラスの名前。指定された場合、そのクラスはValidatorインスタンスを作成するために使用され、その後、接続を検証するためのあらゆる検証クエリの代わりに使用されます。デフォルト値はnullです。例としては、com.mycompany.project.SimpleValidatorがあります。

timeBetweenEvictionRunsMillis

(int) アイドル接続の検証/クリーナースレッドの実行間隔のミリ秒数。この値は1秒未満に設定しないでください。これは、アイドル接続、放棄された接続をチェックする頻度、およびアイドル接続を検証する頻度を決定します。この値は、maxAgeがゼロ以外でより低い値の場合、それに上書きされます。デフォルト値は5000(5秒)です。

numTestsPerEvictionRun

(int) tomcat-jdbc-poolでは使用されないプロパティです。

minEvictableIdleTimeMillis

(int) オブジェクトがプール内でアイドル状態になってから、エビクションの対象となるまでの最小時間。デフォルト値は60000(60秒)です。

accessToUnderlyingConnectionAllowed

(boolean) 使用されないプロパティ。アクセスは、プールされた接続でunwrapを呼び出すことで実現できます。javax.sql.DataSourceインターフェースを参照するか、リフレクションを通じてgetConnectionを呼び出すか、オブジェクトをjavax.sql.PooledConnectionにキャストしてください。

removeAbandoned

(boolean) removeAbandonedTimeoutを超えた場合に放棄された接続を削除するフラグ。trueに設定すると、接続がremoveAbandonedTimeoutよりも長く使用されている場合、その接続は放棄されたものとみなされ、削除の対象となります。これをtrueに設定すると、接続を閉じることができなかったアプリケーションからDB接続を回復できます。logAbandonedも参照してください。デフォルト値はfalseです。

removeAbandonedTimeout

(int) 放棄された(使用中の)接続が削除されるまでのタイムアウト秒数。デフォルト値は60(60秒)です。この値は、アプリケーションが持つ可能性のある最も実行時間の長いクエリに設定する必要があります。

logAbandoned

(boolean) 接続を放棄したアプリケーションコードのスタックトレースをログに記録するフラグ。放棄された接続のロギングは、スタックトレースを生成する必要があるため、接続を借りるたびにオーバーヘッドを追加します。デフォルト値はfalseです。

connectionProperties

(String) 新しい接続を確立する際にJDBCドライバに送信される接続プロパティ。文字列の形式は[propertyName=property;]*である必要があります。注 - "user"と"password"プロパティは明示的に渡されるため、ここに含める必要はありません。デフォルト値はnullです。

poolPreparedStatements

(boolean) 使用されないプロパティです。

maxOpenPreparedStatements

(int) 使用されないプロパティです。

Tomcat JDBC 拡張属性

属性説明
initSQL

(String) 接続が最初に作成されたときに実行されるカスタムクエリ。デフォルト値はnullです。

jdbcInterceptors

(String) org.apache.tomcat.jdbc.pool.JdbcInterceptorクラスを拡張するクラス名のセミコロン区切りリスト。構文と例の詳細については、以下のJDBCインターセプタの設定を参照してください。

これらのインターセプタは、java.sql.Connectionオブジェクト上の操作チェーンにインターセプタとして挿入されます。デフォルト値はnullです。

事前定義されたインターセプタ
org.apache.tomcat.jdbc.pool.interceptor.
ConnectionState
- 自動コミット、読み取り専用、カタログ、およびトランザクション分離レベルを追跡します。
org.apache.tomcat.jdbc.pool.interceptor.
StatementFinalizer
- 開かれたすべてのステートメントを追跡し、接続がプールに返却されたときにそれらを閉じます。

他の事前定義されたインターセプタについては、JDBCインターセプタセクションで詳しく説明されています。

validationInterval

(long) 過剰なバリデーションを避け、この頻度(ミリ秒単位)で最大一度だけバリデーションを実行します。接続がバリデーションの対象であっても、この間隔内で以前にバリデーション済みであれば、再度バリデーションは行われません。デフォルト値は3000(3秒)です。

jmxEnabled

(boolean) プールをJMXに登録するかどうか。デフォルト値はtrueです。

fairQueue

(boolean) getConnectionへの呼び出しが真のFIFO方式で公平に扱われるようにしたい場合にtrueに設定します。これはアイドル接続のリストにorg.apache.tomcat.jdbc.pool.FairBlockingQueue実装を使用します。デフォルト値はtrueです。非同期接続取得を使用する場合、このフラグは必須です。
このフラグを設定すると、スレッドは到着した順序で接続を受け取ることが保証されます。
パフォーマンステスト中、ロックとロック待機の実装方法には非常に大きな違いがあります。fairQueue=trueの場合、システムが実行されているオペレーティングシステムに基づいて意思決定プロセスが行われます。システムがLinux(プロパティos.name=Linux)で実行されている場合、このLinux固有の動作を無効にし、それでも公平なキューを使用するには、コネクションプールクラスがロードされる前に、システムプロパティにorg.apache.tomcat.jdbc.pool.FairBlockingQueue.ignoreOS=trueプロパティを追加するだけです。

abandonWhenPercentageFull

(int) 放棄された(タイムアウトした)接続は、使用中の接続数がabandonWhenPercentageFullで定義されたパーセンテージを超えない限り、閉じられず、報告されません。値は0〜100の間である必要があります。デフォルト値は0で、これはremoveAbandonedTimeoutに達するとすぐに接続がクローズの対象となることを意味します。

maxAge

(long) 接続を再作成するまでの保持時間(ミリ秒)。接続がプールから借りられるとき、プールは現在時刻 - 接続確立時刻 > maxAgeに達しているかどうかを確認し、達していれば、借りる前に再接続します。接続がプールに返却されるとき、プールは現在時刻 - 接続確立時刻 > maxAgeに達しているかどうかを確認し、達していれば、再接続を試みます。接続がアイドル状態であり、timeBetweenEvictionRunsMillisがゼロより大きい場合、プールは定期的に現在時刻 - 接続確立時刻 > maxAgeに達しているかどうかを確認し、達していれば、再接続を試みます。maxAgetimeBetweenEvictionRunsMillisより低い値に設定すると、それがオーバーライドされます(そのため、アイドル接続の検証/クリーニングがより頻繁に実行されます)。デフォルト値は0で、これは接続が開いたままになり、プールから借りる際、プールに接続を返す際、またはアイドル接続をチェックする際に年齢チェックが行われないことを意味します。

useEquals

(boolean) ProxyConnectionクラスがString.equalsを使用することを望む場合にtrueに設定し、メソッド名を比較する際に==を使用することを望む場合にfalseに設定します。このプロパティは、個別設定される追加のインターセプタには適用されません。デフォルト値はtrueです。

suspectTimeout

(int) タイムアウト値(秒)。デフォルト値は0です。
removeAbandonedTimeoutの値に似ていますが、接続を放棄されたものとして扱い、潜在的に接続を閉じるのではなく、logAbandonedがtrueに設定されている場合に警告をログに記録するだけです。この値が0以下の場合、疑わしいチェックは行われません。疑わしいチェックは、タイムアウト値が0より大きく、接続が放棄されていない場合、または放棄チェックが無効になっている場合にのみ行われます。接続が疑わしい場合、WARNメッセージがログに記録され、JMX通知が一度送信されます。

rollbackOnReturn

(boolean) autoCommit==falseの場合、接続がプールに返却される際に、プールは接続に対してロールバックを呼び出すことでトランザクションを終了させることができます。デフォルト値はfalseです。

commitOnReturn

(boolean) autoCommit==falseの場合、接続がプールに返却される際に、プールは接続に対してコミットを呼び出すことでトランザクションを完了させることができます。rollbackOnReturn==trueの場合、この属性は無視されます。デフォルト値はfalseです。

alternateUsernameAllowed

(boolean) デフォルトでは、jdbc-poolはパフォーマンス上の理由から、DataSource.getConnection(username,password)呼び出しを無視し、グローバルに設定されたusernameおよびpasswordプロパティの下で以前にプールされた接続を単純に返します。

ただし、プールは、接続が要求されるたびに異なる資格情報の使用を許可するように設定できます。DataSource.getConnection(username,password)呼び出しで説明されている機能を有効にするには、alternateUsernameAllowedプロパティをtrueに設定するだけです。
user1/password1の資格情報で接続を要求し、その接続が以前に異なるuser2/password2を使用して接続されていた場合、接続は閉じられ、要求された資格情報で再開されます。この方法では、プールサイズはスキーマレベルではなく、グローバルレベルで管理されます。
デフォルト値はfalseです。
このプロパティは、バグ 50025の機能強化として追加されました。

dataSource

(javax.sql.DataSource) コネクションプールにデータソースを注入すると、プールはjava.sql.Driverインターフェースを使用して接続を確立する代わりに、そのデータソースを使用して接続を取得します。これは、XA接続や、接続文字列ではなくデータソースを使用して確立された接続をプールしたい場合に便利です。デフォルト値はnullです。

dataSourceJNDI

(String) JNDIでルックアップされ、その後データベースへの接続確立に使用されるデータソースのJNDI名。dataSource属性を参照してください。デフォルト値はnullです。

useDisposableConnectionFacade

(boolean) 接続が閉じられた後、再利用できないように接続にファサードを適用したい場合にこれをtrueに設定します。これにより、すでにクローズを呼び出した接続の参照を保持しているスレッドが、その接続でクエリを実行するのを防ぎます。デフォルト値はtrueです。

logValidationErrors

(boolean) 検証フェーズ中のエラーをログファイルに記録したい場合にこれをtrueに設定します。trueに設定すると、エラーはSEVEREとしてログに記録されます。下位互換性のため、デフォルト値はfalseです。

propagateInterruptState

(boolean) 中断されたスレッドの中断状態を伝播したい場合(中断状態をクリアしない)にこれをtrueに設定します。下位互換性のため、デフォルト値はfalseです。

ignoreExceptionOnPreLoad

(boolean) プール初期化中の接続作成エラーを無視するかどうかのフラグ。プール初期化中の接続作成エラーを無視したい場合はtrueに設定します。例外をスローしてプールの初期化を失敗させたい場合はfalseに設定します。デフォルト値はfalseです。

useStatementFacade

(boolean) ステートメントプロキシが設定されている場合に、閉じられたステートメントに対してequals()およびhashCode()メソッドが呼び出されるように、ステートメントをラップしたい場合にこれをtrueに設定します。デフォルト値はtrueです。

高度な使用法

JDBCインターセプタ

インターセプタの使用例については、org.apache.tomcat.jdbc.pool.interceptor.ConnectionStateを参照してください。このシンプルなインターセプタは、トランザクション分離レベル、自動コミット、読み取り専用状態という3つの属性のキャッシュであり、システムが不要なデータベースへのラウンドトリップを回避するために使用されます。

必要に応じて、さらに多くのインターセプタがプールのコアに追加されるでしょう。貢献は常に歓迎されます!

インターセプタは当然ながらjava.sql.Connectionに限定されるものではなく、メソッド呼び出しからのあらゆる結果をラップするためにも使用できます。クエリが予想時間を超えて実行されている場合にJMX通知を提供するクエリパフォーマンスアナライザを構築することもできます。

JDBCインターセプタの設定

JDBCインターセプタの設定は、jdbcInterceptors プロパティを使用して行われます。このプロパティには、セミコロンで区切られたクラス名のリストが含まれます。クラス名が完全修飾されていない場合、org.apache.tomcat.jdbc.pool.interceptor.というプレフィックスが付加されます。


jdbcInterceptors="org.apache.tomcat.jdbc.pool.interceptor.ConnectionState; org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer"
と同じです
jdbcInterceptors="ConnectionState;StatementFinalizer"

インターセプタはプロパティを持つこともできます。インターセプタのプロパティは、クラス名の後に括弧内で指定します。複数のプロパティはコンマで区切られます。


jdbcInterceptors="ConnectionState;StatementFinalizer(useEquals=true)"

クラス名、プロパティ名、値の周りの余分な空白文字は無視されます。

org.apache.tomcat.jdbc.pool.JdbcInterceptor

すべてのインターセプタの抽象基底クラスであり、インスタンス化することはできません。

属性説明
useEquals

(boolean) ProxyConnectionクラスがString.equalsを使用することを望む場合にtrueに設定し、メソッド名を比較する際に==を使用することを望む場合にfalseに設定します。デフォルト値はtrueです。

org.apache.tomcat.jdbc.pool.interceptor.ConnectionState

autoCommitreadOnlytransactionIsolationcatalogの各属性について接続をキャッシュします。これは、ゲッターが呼び出されたり、すでに設定されている値でセッターが呼び出されたりしたときに、データベースへのラウンドトリップを回避するためのパフォーマンス強化です。

属性説明

org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer

createStatementprepareStatement、またはprepareCallを使用して作成されたすべてのステートメントを追跡し、接続がプールに返却されたときにこれらのステートメントを閉じます。

属性説明
trace

(boolean as String) 未クローズのステートメントのトレースを有効にします。有効な場合、接続が閉じられたときにステートメントが閉じられていない場合、インターセプターはすべてのスタックトレースをログに記録します。デフォルト値はfalseです。

org.apache.tomcat.jdbc.pool.interceptor.StatementCache

接続上のPreparedStatementおよび/またはCallableStatementインスタンスをキャッシュします。

ステートメントは接続ごとにキャッシュされます。カウント制限は、同じプールに属するすべての接続に対してグローバルにカウントされます。カウントがmaxに達すると、それ以降のステートメントはキャッシュに戻されず、直ちに閉じられます。

属性説明
prepared

(boolean as String) prepareStatement呼び出しを使用して作成されたPreparedStatementインスタンスのキャッシュを有効にします。デフォルト値はtrueです。

callable

(boolean as String) prepareCall呼び出しを使用して作成されたCallableStatementインスタンスのキャッシュを有効にします。デフォルト値はfalseです。

max

(int as String) コネクションプール全体のキャッシュされたステートメント数の上限。デフォルト値は50です。

org.apache.tomcat.jdbc.pool.interceptor.StatementDecoratorInterceptor

48392 を参照。ResultSet.getStatement().getConnection() および Statement.getConnection() メソッドを使用して実際の接続にアクセスするのを防ぐために、ステートメントと結果セットをラップするインターセプタです。

属性説明

org.apache.tomcat.jdbc.pool.interceptor.QueryTimeoutInterceptor

新しいステートメントが作成されると、自動的にjava.sql.Statement.setQueryTimeout(seconds)を呼び出します。プール自体はクエリをタイムアウトさせず、クエリのタイムアウトを強制するのは依然としてJDBCドライバ次第です。

属性説明
queryTimeout

(int as String) クエリタイムアウトに設定する秒数。0以下の値は、この機能を無効にします。デフォルト値は1秒です。

org.apache.tomcat.jdbc.pool.interceptor.SlowQueryReport

クエリのパフォーマンスを追跡し、クエリが時間しきい値を超過するか失敗した場合にログエントリを発行します。使用されるログレベルはWARNです。

属性説明
threshold

(int as String) クエリがログアラートを発行するまでに超えるべきミリ秒数。デフォルト値は1000ミリ秒です。

maxQueries

(int as String) メモリ空間を節約するために追跡するクエリの最大数。0以下の値は、この機能を無効にします。デフォルト値は1000です。

logSlow

(boolean as String) 遅いクエリをログに記録したい場合にtrueに設定します。デフォルト値はtrueです。

logFailed

(boolean as String) 失敗したクエリをログに記録したい場合にtrueに設定します。デフォルト値はfalseです。

org.apache.tomcat.jdbc.pool.interceptor.SlowQueryReportJmx

SlowQueryReportを拡張し、ログエントリに加えて、監視ツールが反応するためのJMX通知を発行します。親クラスのすべての属性を継承します。このクラスはTomcatのJMXエンジンを使用するため、Tomcatコンテナの外部では動作しません。デフォルトでは、JMX通知はConnectionPool mbeanが有効になっている場合に送信されます。SlowQueryReportJmxは、notifyPool=falseの場合、MBeanを登録することもできます。

属性説明
notifyPool

(boolean as String) JMX通知をSlowQueryReportJmx MBeanに送信したい場合はfalseに設定します。デフォルト値はtrueです。

objectName

(String) このオブジェクトをプラットフォームMBeanサーバーに登録するために使用される、有効なjavax.management.ObjectName文字列を定義します。デフォルト値はnullで、オブジェクトはtomcat.jdbc:type=org.apache.tomcat.jdbc.pool.interceptor.SlowQueryReportJmx,name=the-name-of-the-poolを使用して登録されます。

org.apache.tomcat.jdbc.pool.interceptor.ResetAbandonedTimer

放棄タイマーは、接続がプールからチェックアウトされたときに開始されます。これは、30秒のタイムアウトがあり、その接続を使用して10秒のクエリを10回実行した場合、abandonWhenPercentageFull属性に応じて、その接続が放棄されたとマークされ、潜在的に再利用される可能性があることを意味します。このインターセプタを使用すると、接続に対して操作を実行したり、クエリを正常に実行したりするたびに、チェックアウトタイマーがリセットされます。

属性説明

コード例

JDBC使用のためのTomcat設定の他の例は、Tomcatドキュメントにあります。

通常のJava

データソースを作成して使用する簡単な例を以下に示します。

  import java.sql.Connection;
  import java.sql.ResultSet;
  import java.sql.Statement;

  import org.apache.tomcat.jdbc.pool.DataSource;
  import org.apache.tomcat.jdbc.pool.PoolProperties;

  public class SimplePOJOExample {

      public static void main(String[] args) throws Exception {
          PoolProperties p = new PoolProperties();
          p.setUrl("jdbc:mysql://:3306/mysql");
          p.setDriverClassName("com.mysql.jdbc.Driver");
          p.setUsername("root");
          p.setPassword("password");
          p.setJmxEnabled(true);
          p.setTestWhileIdle(false);
          p.setTestOnBorrow(true);
          p.setValidationQuery("SELECT 1");
          p.setTestOnReturn(false);
          p.setValidationInterval(30000);
          p.setTimeBetweenEvictionRunsMillis(30000);
          p.setMaxActive(100);
          p.setInitialSize(10);
          p.setMaxWait(10000);
          p.setRemoveAbandonedTimeout(60);
          p.setMinEvictableIdleTimeMillis(30000);
          p.setMinIdle(10);
          p.setLogAbandoned(true);
          p.setRemoveAbandoned(true);
          p.setJdbcInterceptors(
            "org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;"+
            "org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer");
          DataSource datasource = new DataSource();
          datasource.setPoolProperties(p);

          Connection con = null;
          try {
            con = datasource.getConnection();
            Statement st = con.createStatement();
            ResultSet rs = st.executeQuery("select * from user");
            int cnt = 1;
            while (rs.next()) {
                System.out.println((cnt++)+". Host:" +rs.getString("Host")+
                  " User:"+rs.getString("User")+" Password:"+rs.getString("Password"));
            }
            rs.close();
            st.close();
          } finally {
            if (con!=null) try {con.close();}catch (Exception ignore) {}
          }
      }

  }

リソースとして

JNDIルックアップ用のリソースを設定する方法の例を以下に示します。

<Resource name="jdbc/TestDB"
          auth="Container"
          type="javax.sql.DataSource"
          factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
          testWhileIdle="true"
          testOnBorrow="true"
          testOnReturn="false"
          validationQuery="SELECT 1"
          validationInterval="30000"
          timeBetweenEvictionRunsMillis="30000"
          maxActive="100"
          minIdle="10"
          maxWait="10000"
          initialSize="10"
          removeAbandonedTimeout="60"
          removeAbandoned="true"
          logAbandoned="true"
          minEvictableIdleTimeMillis="30000"
          jmxEnabled="true"
          jdbcInterceptors="org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;
            org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer"
          username="root"
          password="password"
          driverClassName="com.mysql.jdbc.Driver"
          url="jdbc:mysql://:3306/mysql"/>

非同期接続取得

Tomcat JDBC コネクションプールは、プールライブラリに追加のスレッドを追加することなく、非同期接続取得をサポートしています。これは、データソースにFuture<Connection> getConnectionAsync()というメソッドを追加することで実現されます。非同期取得を使用するためには、2つの条件を満たす必要があります。

  1. fairQueueプロパティをtrueに設定する必要があります。
  2. データソースをorg.apache.tomcat.jdbc.pool.DataSourceにキャストする必要があります。
非同期機能の使用例を以下に示します。
  Connection con = null;
  try {
    Future<Connection> future = datasource.getConnectionAsync();
    while (!future.isDone()) {
      System.out.println("Connection is not yet available. Do some background work");
      try {
        Thread.sleep(100); //simulate work
      }catch (InterruptedException x) {
        Thread.currentThread().interrupt();
      }
    }
    con = future.get(); //should return instantly
    Statement st = con.createStatement();
    ResultSet rs = st.executeQuery("select * from user");

インターセプタ

インターセプタは、特定の接続またはそのサブコンポーネントの機能を有効、無効、または変更するための強力な方法です。インターセプタが役立つ多くの異なるユースケースがあります。デフォルトでは、パフォーマンス上の理由から、コネクションプールはステートレスです。プール自体が挿入する唯一の状態は、設定されている場合のdefaultAutoCommitdefaultReadOnlydefaultTransactionIsolationdefaultCatalogです。これらの4つのプロパティは接続作成時にのみ設定されます。接続の使用中にこれらのプロパティが変更された場合でも、プール自体はそれらをリセットしません。

インターセプタはorg.apache.tomcat.jdbc.pool.JdbcInterceptorクラスを拡張する必要があります。このクラスはかなりシンプルで、引数なしのコンストラクタが必要です。

  public JdbcInterceptor() {
  }

接続がプールから借りられると、インターセプタは以下を実装することでイベントを初期化したり、他の方法で反応したりできます。

  public abstract void reset(ConnectionPool parent, PooledConnection con);

メソッド。このメソッドは、コネクションプール自体への参照ConnectionPool parentと、基盤となる接続への参照PooledConnection conという2つの引数で呼び出されます。

java.sql.Connectionオブジェクト上のメソッドが呼び出されると、以下が実行されます。

  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable

メソッドが呼び出されます。Method methodは実際に呼び出されたメソッドであり、Object[] argsは引数です。非常に簡単な例を見てみましょう。接続が閉じられた場合にjava.sql.Connection.close()の呼び出しを何もしないようにする方法を示します。

  if (CLOSE_VAL==method.getName()) {
      if (isClosed()) return null; //noop for already closed.
  }
  return super.invoke(proxy,method,args);

ある観測がなされています。それはメソッド名の比較です。これを行う一つの方法は、"close".equals(method.getName())とすることです。上記では、メソッド名とstatic final String参照との直接的な参照比較が見られます。JVM仕様によれば、メソッド名とstatic final Stringは共有定数プールに格納されるため、参照比較は機能するはずです。もちろん、このようにすることもできます。

  if (compare(CLOSE_VAL,method)) {
      if (isClosed()) return null; //noop for already closed.
  }
  return super.invoke(proxy,method,args);

compare(String,Method)は、インターセプターのuseEqualsフラグを使用し、useEquals=trueフラグが設定されている場合は参照比較または文字列値比較を行います。

プール開始/停止
コネクションプールが開始または閉じられると、通知を受け取ることができます。これはインスタンスメソッドですが、インターセプタクラスごとに一度だけ通知されます。また、現在プールにアタッチされていないインターセプタを使用して通知されます。

  public void poolStarted(ConnectionPool pool) {
  }

  public void poolClosed(ConnectionPool pool) {
  }

これらのメソッドをオーバーライドする際は、JdbcInterceptor以外のクラスを拡張している場合、superを呼び出すことを忘れないでください。

インターセプタの設定
インターセプタは、jdbcInterceptorsプロパティまたはsetJdbcInterceptorsメソッドを使用して設定されます。インターセプタはプロパティを持つことができ、以下のように設定されます。

  String jdbcInterceptors=
    "org.apache.tomcat.jdbc.pool.interceptor.ConnectionState(useEquals=true,fast=yes)"

インターセプタのプロパティ
インターセプタはプロパティを持つことができるため、インターセプタ内でこれらのプロパティの値を読み取れる必要があります。上記のような例では、setPropertiesメソッドをオーバーライドできます。

  public void setProperties(Map<String, InterceptorProperty> properties) {
     super.setProperties(properties);
     final String myprop = "myprop";
     InterceptorProperty p1 = properties.get(myprop);
     if (p1!=null) {
         setMyprop(Long.parseLong(p1.getValue()));
     }
  }

実際のJDBC接続の取得

コネクションプールは、接続を適切にプールするために、実際の接続の周りにラッパーを作成します。また、これらのラッパー内に特定の機能を実行できるようにインターセプタを作成します。実際の接続を取得する必要がある場合は、javax.sql.PooledConnectionインターフェースを使用して取得できます。

  Connection con = datasource.getConnection();
  Connection actual = ((javax.sql.PooledConnection)con).getConnection();

ビルド

JDBCプールコードは1.6でビルドされていますが、ランタイム環境では1.5まで下位互換性があります。単体テストでは1.6以上を使用しています。

JDBC使用のためのTomcat設定の他の例は、Tomcatドキュメントにあります。

ソースからのビルド

ビルドは非常に簡単です。プールはtomcat-juli.jarに依存しており、SlowQueryReportJmxが必要な場合も同様です。

  javac -classpath tomcat-juli.jar \
        -d . \
        org/apache/tomcat/jdbc/pool/*.java \
        org/apache/tomcat/jdbc/pool/interceptor/*.java \
        org/apache/tomcat/jdbc/pool/jmx/*.java

ビルドファイルはTomcatのソースリポジトリにあります。

便宜上、シンプルなビルドコマンドで必要なすべてのファイルを生成するビルドファイルも含まれています。

  ant download  (downloads dependencies)
  ant build     (compiles and generates .jar files)
  ant dist      (creates a release package)
  ant test      (runs tests, expects a test database to be setup)

システムはMavenビルド用に構成されていますが、リリースアーティファクトを生成します。ライブラリ自体のみです。