Tomcat JDBC Connection Poolの存在を忘れてました

# はじめに

少し前まで業務でSeasar2 FWを使っていたためコネクションプールはSeasar2のものを利用していました。S2のコネクションプールの実装はシンプルだったし業務で利用していても特にそこがボトルネックになることはありませんでした。
別のプロジェクトに移ってDBCPを触っていたのですが、実装になんとなく疑問を感じたので調べてみました。

# tomcat jdbc connection poolとは？

* tomcatで実装したConnectionPoolの実装です。（DBCPとは異なります。）
* tomcat 7.0.19から利用できます。
* tomat-jdbc.jarに含まれています。
* DBCPからの切り替えはfactoryを変更するだけです。
* tomcatのdefaultではDBCPが選択されていますので明示的に変更が必要です。

```
factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
```

# どこに違いがあるのか。

## パフォーマンス

* DBCPよりパフォーマンスが優れています。
* connectionを取得して簡単なSQLを投げてCloseする。という流れを1000回投げてみたところ、DBCPでは平均33msecでしたが、tomcat jdbc poolは平均10msecでした。
* ThreadPoolを使って同時5スレッドで試しましたが性能差は同様でした。

## 設定値に対する内部動作

* 設定値の意味については基本的に違いはありませんが、内部ではいろいろ違います。
* 例えばDBCPではシングルスレッドで動きgetConnection時にsynchronizedをかけてコネクションのチェック処理＆取得を行っているようです。jdbc connection poolはconnectionの利用を監視している部分は別のThreadで行っており、この点からもパフォーマンス的にはよさそうでした。
* 細かい点で動きが違う点を挙げておきます。
* 初期のコネクションプールのサイズを決めるinitialsizeを0、minIdleを10としたときにDBCPではminIdleの設定(10)が有効になりますが、dbcpではinitialsizeが0であれば起動時は0になり利用される度にminIdle以下であれば保持するような動きをするようです。

## Interceptor

* Interceptorを挟むことができます。Statementに対して一律QueryTimeoutを設定するとか、遅いSQLを抽出することができます。SlowQueryはDBの設定を変えなくてもできるようになりますね。
* [org.apache.tomcat.jdbc.pool.interceptor.ConnectionState](http://tomcat.apache.org/tomcat-8.0-doc/jdbc-pool.html#org.apache.tomcat.jdbc.pool.interceptor.ConnectionState)
* [org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer]()
* [org.apache.tomcat.jdbc.pool.interceptor.StatementCache](http://tomcat.apache.org/tomcat-8.0-doc/jdbc-pool.html#org.apache.tomcat.jdbc.pool.interceptor.StatementCache)
* [org.apache.tomcat.jdbc.pool.interceptor.StatementDecoratorInterceptor](http://tomcat.apache.org/tomcat-8.0-doc/jdbc-pool.html#org.apache.tomcat.jdbc.pool.interceptor.StatementDecoratorInterceptor)
* [org.apache.tomcat.jdbc.pool.interceptor.QueryTimeoutInterceptor](http://tomcat.apache.org/tomcat-8.0-doc/jdbc-pool.html#org.apache.tomcat.jdbc.pool.interceptor.QueryTimeoutInterceptor)
* [org.apache.tomcat.jdbc.pool.interceptor.SlowQueryReport](http://tomcat.apache.org/tomcat-8.0-doc/jdbc-pool.html#org.apache.tomcat.jdbc.pool.interceptor.SlowQueryReport)
* [org.apache.tomcat.jdbc.pool.interceptor.SlowQueryReportJmx](http://tomcat.apache.org/tomcat-8.0-doc/jdbc-pool.html#org.apache.tomcat.jdbc.pool.interceptor.SlowQueryReportJmx)
* [org.apache.tomcat.jdbc.pool.interceptor.ResetAbandonedTimer](http://tomcat.apache.org/tomcat-8.0-doc/jdbc-pool.html#org.apache.tomcat.jdbc.pool.interceptor.ResetAbandonedTimer)

## Interceptorを使う

* QueryTimeoutInterceptorを利用してQueryTimeoutを設定するには以下のようにします。
* package名は省略することが可能です。引数は()内に記載します。

```
jdbcInterceptors="QueryTimeoutInterceptor(queryTimeout=10)"
```


## 独自のInterceptorを作る

* org.apache.tomcat.jdbc.pool.JdbcInterceptorを実装するだけです。
* tomcat-jdbcはtomcat-juli.jarのみに依存していますのでそれだけ依存関係に追加しておきましょう。
* [Commons DBCPを超えるTomcat JDBC Poolとは ](http://www.atmarkit.co.jp/ait/articles/1111/07/news212_2.html)

## JMX

* jconsoleでtomcatを叩くとjmx経由でdatasourceの情報が取得できます。
* DBCPでできる操作はremoveConnectionProperty,addConnectionProperty,getConnection closeです。
* tomcat jdbc connection poolでは、checkIdle,testIdle,checkAbandonedを操作できます。

# パラメータについて(tomcat jdbc pool）

| 属性 | 説明 |設定例|
|:-----------|:------------|:-----------|
|type|javax.sql.DataSource||
|driverClassName|JDBCドライバのクラス名|
|url|接続URL|
|username|データベースに接続するユーザ名|
|password|データベースに接続するパスワード|
|factory|org.apache.tomcat.jdbc.pool.DataSourceFactory|
|jdbcInterceptors|Interceptorのクラス名と引数を指定する。複数記載するときには;(セミコロン）で区切る|例）QueryTimeoutInterceptor(queryTimeout=10)　|
|initialSize|tomcat起動時に作成するプールの初期値|10|
|maxActive|データベース接続の最大数|100|
|minIdle|アイドルするコネクションの最小数|10|
|maxIdle|アイドルするコネクションの最大数|50|
|testWhileIdle|コネクションの有効性を確認するか否か|true|
|testOnBorrow|プールからコネクションを取得する際に有効性を確認するか否か|true|
|testOnReturn|プールにコネクションを返却する際に有効性を確認するか否か|true|
|validationQuery|有効性を確認するときのSQLを指定する|
|validationInterval|有効性を確認する間隔を指定する|15(sec)|
|timeBetweenEvictionRunsMillis|指定した間隔でコネクションの有効性確認を行う。tomcat7.0.23で確認したところminIdleまで減るが、minIdle以下の場合minIdleにまで増やすことは行わない|15000(msec)|
|minEvictableIdleTimeMillis|アイドル接続しているコネクションの生存時間|msec|
|removeAbandoned|removeAbandonedTimeoutを過ぎたコネクションを自動で切断するか否か。この時切断したコネクションはプールに戻らないので注意が必要。|true|
|removeAbandonedTimeout|コネクションを切断するまでの時間|10(sec)|
|poolPreparedStatements|利用不可|
|maxOpenPreparedStatements|利用不可|
|numTestsPerEvictionRun|利用不可|