- はじめに
- 使用方法
- 属性
- 高度な使用法
- JDBCインターセプタ
- JDBCインターセプタの設定
- org.apache.tomcat.jdbc.pool.JdbcInterceptor
- org.apache.tomcat.jdbc.pool.interceptor.ConnectionState
- org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer
- org.apache.tomcat.jdbc.pool.interceptor.StatementCache
- org.apache.tomcat.jdbc.pool.interceptor.StatementDecoratorInterceptor
- org.apache.tomcat.jdbc.pool.interceptor.QueryTimeoutInterceptor
- org.apache.tomcat.jdbc.pool.interceptor.SlowQueryReport
- org.apache.tomcat.jdbc.pool.interceptor.SlowQueryReportJmx
- org.apache.tomcat.jdbc.pool.interceptor.ResetAbandonedTimer
- コード例
- ビルド
Tomcat JDBC コネクションプール
目次
はじめに
JDBC Connection Pool org.apache.tomcat.jdbc.pool
は、Apache Commons DBCP コネクションプール の代替または置き換えとなるものです。
では、なぜ新しいコネクションプールが必要なのでしょうか?
理由をいくつかご紹介します
- Commons DBCP 1.x はシングルスレッドです。スレッドセーフであるためには、Commons はオブジェクトの割り当てと返却の両方において、短時間プール全体をロックします。これは Commons DBCP 2.x には当てはまりません。
- Commons DBCP 1.x は遅い場合があります。論理CPUの数が増え、オブジェクトを借りたり返したりしようとする同時実行スレッドの数が増加するにつれて、パフォーマンスが低下します。高並行システムでは、その影響は重大になる可能性があります。これは Commons DBCP 2.x には当てはまりません。
- Commons DBCP は60以上のクラスで構成されています。tomcat-jdbc-pool のコアは8クラスであり、将来の要件に対する変更ははるかに少ない変更で済みます。これだけでコネクションプール自体を実行でき、残りは付加的なものです。
- Commons DBCP は静的インターフェースを使用します。これは、特定のJREバージョンに対して適切なバージョンを使用しないと、
NoSuchMethodException
例外が発生する可能性があることを意味します。 - コネクションプールがはるかにシンプルな実装で実現できるのに、60以上のクラスを書き直す価値はありません。
- Tomcat JDBC プールは、ライブラリ自体に追加のスレッドを追加することなく、接続を非同期で取得する機能を実装しています。
- Tomcat JDBC プールはTomcatモジュールであり、Tomcatで使用される簡素化されたロギングフレームワークであるTomcat JULIに依存しています。
javax.sql.PooledConnection
インターフェースを使用して、基盤となる接続を取得します。- スタベーション耐性があります。プールが空でスレッドが接続を待っている場合、接続が返却されると、プールは待機中の正しいスレッドを起動します。ほとんどのプールは単にスタベーションに陥ります。
他のコネクションプール実装に追加された機能
- 高並行環境およびマルチコア/CPUシステムをサポートします。
- インターフェースの動的実装により、より低いバージョンのJDKでコンパイルされた場合でも、ランタイム環境の
java.sql
およびjavax.sql
インターフェースをサポートします(JDBCドライバも同様である限り)。 - バリデーション間隔 - 接続を使用するたびにバリデーションを行う必要はなく、接続を借りたり返したりするときに行うことができますが、設定可能な間隔よりも頻繁に行うことはありません。
- 一度だけ実行されるクエリ - データベースへの接続が確立されたときに一度だけ実行される設定可能なクエリです。接続が確立されている間ずっと存在させたいセッション設定を行うのに非常に便利です。
- カスタムインターセプタを設定する機能。これにより、カスタムインターセプタを記述して機能を拡張できます。インターセプタを使用して、クエリ統計の収集、セッション状態のキャッシュ、障害発生時の接続の再接続、クエリの再試行、クエリ結果のキャッシュなどを行うことができます。選択肢は無限であり、インターセプタは動的で、
java.sql
/javax.sql
インターフェースのJDKバージョンに縛られません。 - 高パフォーマンス - パフォーマンスの違いについては後述します
- 非常にシンプル - 非常に簡素化された実装のため、行数とソースファイル数が非常に少なく、(最後に確認した時点では)200以上のソースファイルを持つc3p0と比較して、Tomcat JDBCのコアは8ファイルで、コネクションプール自体はその約半分です。バグが発生した場合でも、追跡が速く、修正が容易になります。複雑性の軽減は、当初から重点が置かれてきました。
- 非同期接続取得 - 接続要求をキューに入れ、
Future<Connection>
を受け取ることができます。 - より良いアイドル接続処理。接続を直接閉じる代わりに、引き続き接続をプールし、より賢いアルゴリズムでアイドルプールをサイジングできます。
- 接続が放棄されたとみなされるタイミングを決定できます。それはプールが満杯になったときか、またはプール使用しきい値を指定して直接タイムアウトしたときかです。
- ステートメント/クエリのアクティビティが発生すると、放棄接続タイマーはリセットされます。これにより、長期間使用されている接続がタイムアウトしないようにします。これは
ResetAbandonedTimer
を使用して実現されます。 - 一定時間接続された後、接続を閉じます。プールに戻ったときに、経過時間に基づいて閉じます。
- 接続が放棄された疑いがある場合にJMX通知とログエントリを取得します。これは
removeAbandonedTimeout
に似ていますが、アクションは実行せず、情報のみを報告します。これはsuspectTimeout
属性を使用して実現されます。 - 接続は
java.sql.Driver
、javax.sql.DataSource
またはjavax.sql.XADataSource
から取得できます。これはdataSource
およびdataSourceJNDI
属性を使用して実現されます。 - 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 |
|
type |
Typeは常に 型に応じて、 |
システムプロパティ
システムプロパティはJVM全体に適用され、JVM内で作成されたすべてのプールに影響します。
属性 | 説明 |
---|---|
org.apache.tomcat.jdbc.pool.onlyAttemptCurrentClassLoader |
(boolean) JDBCドライバ、インターセプタ、バリデータなどの動的クラスのクラスローディングを制御します。 |
共通属性
これらの属性は commons-dbcp と tomcat-jdbc-pool で共有されますが、場合によってはデフォルト値が異なります。
属性 | 説明 |
---|---|
defaultAutoCommit |
(boolean) このプールによって作成される接続のデフォルトの自動コミット状態。設定されていない場合、デフォルトはJDBCドライバのデフォルトです(設定されていない場合、 |
defaultReadOnly |
(boolean) このプールによって作成される接続のデフォルトの読み取り専用状態。設定されていない場合、 |
defaultTransactionIsolation |
(String) このプールによって作成される接続のデフォルトのトランザクション分離状態。以下のいずれかです。(javadocを参照)
設定されていない場合、このメソッドは呼び出されず、JDBCドライバのデフォルトが使用されます。 |
defaultCatalog |
(String) このプールによって作成される接続のデフォルトカタログ。 |
driverClassName |
(String) 使用するJDBCドライバの完全修飾Javaクラス名。ドライバはtomcat-jdbc.jarと同じクラスローダーからアクセス可能である必要があります。 |
username |
(String) 接続を確立するためにJDBCドライバに渡される接続ユーザー名。デフォルトでは、 |
password |
(String) 接続を確立するためにJDBCドライバに渡される接続パスワード。デフォルトでは、 |
maxActive |
(int) このプールから同時に割り当てることができるアクティブ接続の最大数。デフォルト値は |
maxIdle |
(int) プール内に常に保持されるべき接続の最大数。デフォルト値は |
minIdle |
(int) プール内に常に保持されるべき確立された接続の最小数。バリデーションクエリが失敗した場合、コネクションプールはこの数を下回ることがあります。デフォルト値は |
initialSize |
(int) プールが起動したときに作成される初期接続数。デフォルト値は |
maxWait |
(int) 利用可能な接続がない場合、例外をスローする前に、プールが接続が返却されるのを待つ最大ミリ秒数。デフォルト値は |
testOnBorrow |
(boolean) プールからオブジェクトを借りる前に、そのオブジェクトが検証されるかどうかを示すフラグです。オブジェクトの検証に失敗した場合、そのオブジェクトはプールから削除され、別のオブジェクトを借りようとします。より効率的な検証を行うには、 |
testOnConnect |
(boolean) 接続が最初に作成されるときにオブジェクトが検証されるかどうかを示すフラグ。オブジェクトの検証に失敗した場合、 |
testOnReturn |
(boolean) プールに返却する前にオブジェクトが検証されるかどうかを示すフラグ。デフォルト値は |
testWhileIdle |
(boolean) アイドルオブジェクトのエビクター(存在する場合)によってオブジェクトが検証されるかどうかを示すフラグ。オブジェクトの検証に失敗した場合、プールから削除されます。デフォルト値は |
validationQuery |
(String) このプールから接続を呼び出し元に返す前に、接続を検証するために使用されるSQLクエリ。指定された場合、このクエリはデータを返す必要はなく、単に |
validationQueryTimeout |
(int) 接続検証クエリが失敗するまでのタイムアウト秒数。これは、 |
validatorClassName |
(String) |
timeBetweenEvictionRunsMillis |
(int) アイドル接続の検証/クリーナースレッドの実行間隔のミリ秒数。この値は1秒未満に設定しないでください。これは、アイドル接続、放棄された接続をチェックする頻度、およびアイドル接続を検証する頻度を決定します。この値は、 |
numTestsPerEvictionRun |
(int) tomcat-jdbc-poolでは使用されないプロパティです。 |
minEvictableIdleTimeMillis |
(int) オブジェクトがプール内でアイドル状態になってから、エビクションの対象となるまでの最小時間。デフォルト値は |
accessToUnderlyingConnectionAllowed |
(boolean) 使用されないプロパティ。アクセスは、プールされた接続で |
removeAbandoned |
(boolean) |
removeAbandonedTimeout |
(int) 放棄された(使用中の)接続が削除されるまでのタイムアウト秒数。デフォルト値は |
logAbandoned |
(boolean) 接続を放棄したアプリケーションコードのスタックトレースをログに記録するフラグ。放棄された接続のロギングは、スタックトレースを生成する必要があるため、接続を借りるたびにオーバーヘッドを追加します。デフォルト値は |
connectionProperties |
(String) 新しい接続を確立する際にJDBCドライバに送信される接続プロパティ。文字列の形式は[propertyName=property;]*である必要があります。注 - "user"と"password"プロパティは明示的に渡されるため、ここに含める必要はありません。デフォルト値は |
poolPreparedStatements |
(boolean) 使用されないプロパティです。 |
maxOpenPreparedStatements |
(int) 使用されないプロパティです。 |
Tomcat JDBC 拡張属性
属性 | 説明 |
---|---|
initSQL |
(String) 接続が最初に作成されたときに実行されるカスタムクエリ。デフォルト値は |
jdbcInterceptors |
(String) これらのインターセプタは、 事前定義されたインターセプタ 他の事前定義されたインターセプタについては、JDBCインターセプタセクションで詳しく説明されています。 |
validationInterval |
(long) 過剰なバリデーションを避け、この頻度(ミリ秒単位)で最大一度だけバリデーションを実行します。接続がバリデーションの対象であっても、この間隔内で以前にバリデーション済みであれば、再度バリデーションは行われません。デフォルト値は |
jmxEnabled |
(boolean) プールをJMXに登録するかどうか。デフォルト値は |
fairQueue |
(boolean) getConnectionへの呼び出しが真のFIFO方式で公平に扱われるようにしたい場合にtrueに設定します。これはアイドル接続のリストに |
abandonWhenPercentageFull |
(int) 放棄された(タイムアウトした)接続は、使用中の接続数が |
maxAge |
(long) 接続を再作成するまでの保持時間(ミリ秒)。接続がプールから借りられるとき、プールは |
useEquals |
(boolean) |
suspectTimeout |
(int) タイムアウト値(秒)。デフォルト値は |
rollbackOnReturn |
(boolean) |
commitOnReturn |
(boolean) |
alternateUsernameAllowed |
(boolean) デフォルトでは、jdbc-poolはパフォーマンス上の理由から、 ただし、プールは、接続が要求されるたびに異なる資格情報の使用を許可するように設定できます。 |
dataSource |
(javax.sql.DataSource) コネクションプールにデータソースを注入すると、プールは |
dataSourceJNDI |
(String) JNDIでルックアップされ、その後データベースへの接続確立に使用されるデータソースのJNDI名。 |
useDisposableConnectionFacade |
(boolean) 接続が閉じられた後、再利用できないように接続にファサードを適用したい場合にこれをtrueに設定します。これにより、すでにクローズを呼び出した接続の参照を保持しているスレッドが、その接続でクエリを実行するのを防ぎます。デフォルト値は |
logValidationErrors |
(boolean) 検証フェーズ中のエラーをログファイルに記録したい場合にこれをtrueに設定します。trueに設定すると、エラーはSEVEREとしてログに記録されます。下位互換性のため、デフォルト値は |
propagateInterruptState |
(boolean) 中断されたスレッドの中断状態を伝播したい場合(中断状態をクリアしない)にこれをtrueに設定します。下位互換性のため、デフォルト値は |
ignoreExceptionOnPreLoad |
(boolean) プール初期化中の接続作成エラーを無視するかどうかのフラグ。プール初期化中の接続作成エラーを無視したい場合はtrueに設定します。例外をスローしてプールの初期化を失敗させたい場合はfalseに設定します。デフォルト値は |
useStatementFacade |
(boolean) ステートメントプロキシが設定されている場合に、閉じられたステートメントに対して |
高度な使用法
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) |
org.apache.tomcat.jdbc.pool.interceptor.ConnectionState
autoCommit
、readOnly
、transactionIsolation
、catalog
の各属性について接続をキャッシュします。これは、ゲッターが呼び出されたり、すでに設定されている値でセッターが呼び出されたりしたときに、データベースへのラウンドトリップを回避するためのパフォーマンス強化です。
属性 | 説明 |
---|
org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer
createStatement
、prepareStatement
、またはprepareCall
を使用して作成されたすべてのステートメントを追跡し、接続がプールに返却されたときにこれらのステートメントを閉じます。
属性 | 説明 |
---|---|
trace |
(boolean as String) 未クローズのステートメントのトレースを有効にします。有効な場合、接続が閉じられたときにステートメントが閉じられていない場合、インターセプターはすべてのスタックトレースをログに記録します。デフォルト値は |
org.apache.tomcat.jdbc.pool.interceptor.StatementCache
接続上のPreparedStatement
および/またはCallableStatement
インスタンスをキャッシュします。
ステートメントは接続ごとにキャッシュされます。カウント制限は、同じプールに属するすべての接続に対してグローバルにカウントされます。カウントがmax
に達すると、それ以降のステートメントはキャッシュに戻されず、直ちに閉じられます。
属性 | 説明 |
---|---|
prepared |
(boolean as String) |
callable |
(boolean as String) |
max |
(int as String) コネクションプール全体のキャッシュされたステートメント数の上限。デフォルト値は |
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以下の値は、この機能を無効にします。デフォルト値は |
org.apache.tomcat.jdbc.pool.interceptor.SlowQueryReport
クエリのパフォーマンスを追跡し、クエリが時間しきい値を超過するか失敗した場合にログエントリを発行します。使用されるログレベルはWARN
です。
属性 | 説明 |
---|---|
threshold |
(int as String) クエリがログアラートを発行するまでに超えるべきミリ秒数。デフォルト値は |
maxQueries |
(int as String) メモリ空間を節約するために追跡するクエリの最大数。0以下の値は、この機能を無効にします。デフォルト値は |
logSlow |
(boolean as String) 遅いクエリをログに記録したい場合に |
logFailed |
(boolean as String) 失敗したクエリをログに記録したい場合に |
org.apache.tomcat.jdbc.pool.interceptor.SlowQueryReportJmx
SlowQueryReport
を拡張し、ログエントリに加えて、監視ツールが反応するためのJMX通知を発行します。親クラスのすべての属性を継承します。このクラスはTomcatのJMXエンジンを使用するため、Tomcatコンテナの外部では動作しません。デフォルトでは、JMX通知はConnectionPool mbeanが有効になっている場合に送信されます。SlowQueryReportJmx
は、notifyPool=false
の場合、MBeanを登録することもできます。
属性 | 説明 |
---|---|
notifyPool |
(boolean as String) JMX通知を |
objectName |
(String) このオブジェクトをプラットフォームMBeanサーバーに登録するために使用される、有効な |
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つの条件を満たす必要があります。
fairQueue
プロパティをtrue
に設定する必要があります。- データソースを
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");
インターセプタ
インターセプタは、特定の接続またはそのサブコンポーネントの機能を有効、無効、または変更するための強力な方法です。インターセプタが役立つ多くの異なるユースケースがあります。デフォルトでは、パフォーマンス上の理由から、コネクションプールはステートレスです。プール自体が挿入する唯一の状態は、設定されている場合のdefaultAutoCommit
、defaultReadOnly
、defaultTransactionIsolation
、defaultCatalog
です。これらの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ビルド用に構成されていますが、リリースアーティファクトを生成します。ライブラリ自体のみです。