WAS接続プールのパージ(破棄)が起きるDb2エラーコードの調べ方

## 前置き

WebSphere Application Server(WAS)は現在 tWAS, Liberty の大きく2製品ありますが、DB接続にあたって「接続プール」を持ち、一度確立した接続を使いまわす仕組みを持っていることは共通しています。

設定できるパラメータも概ね変わりがなく見えますが、デフォルトのLibertyでは使えなくなっている機能や設定があり、完全に同じものとも言えません。

WASの接続プールが提供する重要な機能として「接続障害が起きたら、プール内の接続をパージする(デフォルトでは一括削除)」機能がありますが、tWASとLiberty、全く同じDBエラーコードを識別するのでしょうか？

tWASではマニュアルにJavaDocが含まれていてドキュメントベースで接続パージ対象となるDBエラーコードを参照できていたのですが、Libertyマニュアルにはこれに対応する情報を見つけられずどう調べるか困ったため、自分用のメモとして確認方法と今回確認したエラーコードを残しておこうと思います。

## 接続プールとは

WAS上でDBアクセスを行う場合、アプリからgetConnectionメソッドを実行することで接続オブジェクトを取得し、DBアクセスを行います。
接続オブジェクトは、WASを起動しただけでは作成されず、アプリからのDBに対する初回の接続要求があった時はじめて作成されます。そして、作成された接続オブジェクトは、使い終わったあと、再び使いまわせるように接続プールに戻されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/468682/b8ca87a6-7815-5af3-9c2f-1cf7216ebbe6.png)

接続を確立する処理はDBサーバーにとって負荷がかかる処理であるため、DBサーバとの接続を維持した状態のままプールに戻しておくことで、また同じDBへのアクセスが必要になった場合も、プールから接続を取り出すだけですぐに再利用することができます。

しかし、ここでDBサーバやネットワークがダウンしてしまうと、プールには使えないプールがいくつも残ってしまうことになります。そこで一度接続エラーが起きたら、同じDBサーバに接続されている、プール済の接続はすべて削除される実装となっています(tWASならびにLibertyのデフォルト、PurgePolicy=EntirePool)。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/468682/602606da-1926-16b2-d5e0-7843cd7dd046.png)


WASにおいて "接続エラー"とみなされ、その結果として接続オブジェクトが破棄されるのは、接続オブジェクト(またはステートメント)が「Stale Connection」であると判断された時です。

では、「Stale Connection」とは具体的に何を指すか？
Db2では何らか異常があればエラーコードを返してくれますが、そのうちどのコードを、WASは「Stale」と判定しているのでしょう。


## 「Stale」と判定されるDb2エラーコード

### WAS(tWAS)の場合
tWAS では、失効状態のConnection  オブジェクトをアプリケーションから再利用しようとすると、 StaleConnectionException という、IBM固有の例外クラスにマッピングされアプリケーションに戻されます(※1)。またStaleConnectionException 発生時には接続プール内の未使用接続も含め、すべて一括破棄されます(※2)。

(※1)エラー検出モデルが例外マッピングを実行するように構成されている場合(デフォルト)
(※2)パージポリシー=EntirePool(デフォルト)



tWAS が StaleConnectionException にマッピングする Db2のエラーコードはDb2用DataStoreHelperクラスのJavaDocに記載があります。
 * [JavaDoc: com.ibm.websphere.rsadapter.DB2UniversalDataStoreHelper](https://www.ibm.com/docs/api/v1/content/SSEQTJ_9.0.5/com.ibm.websphere.javadoc.doc/web/apidocs/com/ibm/websphere/rsadapter/DB2UniversalDataStoreHelper.html)
 * [JavaDoc: com.ibm.websphere.rsadapter.DB2DataStoreHelper](https://www.ibm.com/docs/api/v1/content/SSEQTJ_9.0.5/com.ibm.websphere.javadoc.doc/web/apidocs/com/ibm/websphere/rsadapter/DB2DataStoreHelper.html)


### Libertyの場合
LibertyではStaleConnectionExceptionはスローされません(※3)。これはJDBC 4.0における仕様変更/拡充により、より詳細なSQLExceptionクラスが標準で提供されることになったことを受けたもののようです。(より状況を的確に示すSQLExceptionのサブクラスがスローされるようになったため、今後はそれらをハンドリングしていく)
 * [Instructions to replace com.ibm.websphere.ce.cm/j2c exceptions #8349](https://github.com/OpenLiberty/open-liberty/issues/8349)

この変更にかかわらず、Stale Connection, パージポリシーという概念やそれに伴う動作自体はLibertyにも同様に引き継がれており、接続エラーが発生した後、tWAS同様、失効状態と判断された Connection オブジェクトは破棄されます。

では、どの種類のエラーが発生した場合にLibertyはStaleとみなすか？マニュアルにあるといいのですが、今のところ発見できていません。
その代わり、Libertyの接続プールトレースに出力されます。

(※3)LibertyでもtWAS上で稼働していたアプリをLibertyに移植する場合に引き続きStaleConnectionExceptionを利用する方法もあるようです。
　→ [WebSphere Liberty で StaleConnectionException を利用する](https://qiita.com/splendormy/items/c06e73f3d15374906daa)


#### Liberty上で「Stale」と判定される Db2 エラーコードの調査ログ

バージョンはやや古いですが、以下の環境で確認した結果を貼っておきます。


##### 確認した環境
 * WebSphere Application Server 22.0.0.7 (wlp-1.0.66.cl220720220620-2217)
* JDBC Driver: IBM Data Server Driver for JDBC and SQLJ 4.31.10
* Db2 Server: Db2 11.5.7.0
* トレース設定手順は[こちら]()に記載

##### 確認結果

Liberty trace.log より抜粋。

| Db2 JDBC ERRORCODE |
|:-|
| -60161, 40003, -1224, -1034, -906, -1035, 55032, -1229, -1776, 08006, -4498, -4499, 08S01, -6036, 58004, 08003, -1015, 08001, -923, -30108, -924  |


接続先DBMSがDb2であり、上記エラーが発生した場合に、Liberty接続がパージ(削除)されるということです。

補足として、trace.logの原文も添付しておきます。
```text: trace.logからの原文添付
exception identification
stale connection: [-60161, 40003, -1224, -1034, -906, -1035, 55032, -1229, -1776, 08006, -4498, -4499, 08S01, -6036, 58004, 08003, -1015, 08001, -923, -30108, -924]
stale statement:  [-514, -518]
```

なお、2行目に出力される "stale statement" の行については、PreparedStatementCacheの失効などに伴い発生するエラーコードであり、少なくともSQL0514N発生時ではキャッシュされている失効ステートメントは破棄されるものの接続自体には問題がない状態(接続エラーではない)であり、接続は破棄(パージ)されません。これはこれで、プールされた接続オブジェクトの数だけエラーが起きる事態を招いて問題となることがありますが、長くなるのでまた別途。

## パージされる単位(1接続 or プールされている全接続)
前述のDB2 ERRORCODEによって接続オブジェクトが破棄される場合、このエラーをまさに戻されたアプリがつかんでいた接続オブジェクトだけが破棄されるか、その時点でプールに入っている接続オブジェクトもすべて破棄されるかは、パージポリシーに依存します。

tWASもLibertyもデフォルトのパージポリシーはEntirePoolであり、その時点で残っているプール済の接続オブジェクトは、全て破棄されます。


## 参考ドキュメント

 * [WebSphere Libertyマニュアル「データ・アクセスに関する例外」
](https://www.ibm.com/docs/ja/was-nd/9.0.5?topic=resources-exceptions-pertaining-data-access)
* [WebSphere Libertyマニュアル「データ・ソース (dataSource)」](https://www.ibm.com/docs/ja/was-liberty/nd?topic=configuration-datasource)

[](LibertyにおいてDb2接続プールがパージされる条件)