JNDI・JDBC・JTA
データソースを定義し、JNDIから取得します。共有とwebapp専用の違い、トランザクションの保証範囲を確認します。
JNDIの名前
webappの実行コンテキストから new InitialContext().lookup(...) を使います。@Resource 等の自動注入に全面的に依存する構成は現行の対応範囲ではありません。
| 名前 | 型・用途 |
|---|---|
| java:comp/env/<name> | env-entry、DataSource等のアプリ環境項目 |
| java:comp/UserTransaction | javax.transaction.UserTransaction |
| java:comp/TransactionSynchronizationRegistry | javax.transaction.TransactionSynchronizationRegistry |
| java:comp/DefaultContextService | javax.enterprise.concurrent.ContextService |
| java:comp/DefaultManagedExecutorService | javax.enterprise.concurrent.ManagedExecutorService |
| java:comp/DefaultManagedScheduledExecutorService | javax.enterprise.concurrent.ManagedScheduledExecutorService |
| java:comp/DefaultManagedThreadFactory | javax.enterprise.concurrent.ManagedThreadFactory |
サーバ共有のDataSource
conf/resources.yaml に定義します。同じ名前を参照するwebappは同じプールと接続上限を共有します。ドライバはサーバ側で読み込むため lib/ に置きます。下は接続先を置換して使う非XA例です。
dataSource:
"jdbc/app":
url: "jdbc:postgresql://db.example.invalid:5432/app"
driverClass: org.postgresql.Driver
user: app
password: "CHANGE-ME"
maxConnections: 8
maxIdle: 8
borrowTimeoutMillis: 30000
validationQuery: "SELECT 1"
queryLog: "off"
connectionProperty:
ApplicationName: kohaku-app<resource-ref>
<res-ref-name>jdbc/app</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
<res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>DataSource型のresource-refに対応する定義がない場合、参照するwebappの配備が失敗します。定義の不正値やドライバ読込失敗もそのwebappの配備失敗です。未参照の不正定義だけでサーバ全体を止めることはありません。ただしresources.yamlそのものの読込・構文エラーは起動失敗です。
| 項目 | 既定・条件 |
|---|---|
| url / driverClass | 非XAで必須。driverClassを明示しDriver#connectを呼ぶ |
| user / password | 未指定。userを省略するとpasswordも渡さない |
| maxConnections | 8。正数。停滞・物理close失敗の接続も上限に数える |
| maxIdle | 8。非負かつmaxConnections以下。接続上限だけを8未満にするならこちらも指定 |
| borrowTimeoutMillis | 30000。非負・ミリ秒。空き待ちと検証・確立で同じ全体予算。検証・確立には最低1秒 |
| validationQuery | 未設定。無ければConnection.isValidで生存確認 |
| queryLog | off / safe / hash / unsafe-full |
| connectionProperty.<name> | 非XA用。user/password・空の値は不可。単位と意味はドライバ固有 |
| xa.dataSourceClass | XADataSourceの実装。XAではurl/driverClassを使わない |
| xa.property.<name> | XADataSourceのJavaBeansプロパティ。XA定義でconnectionPropertyは不可 |
webapp専用のDataSource
WAR内の WEB-INF/kohaku-web.xml へ定義し、ドライバjarは WEB-INF/lib/ に置きます。同名の共有定義があればローカル定義が優先され、接続先と資格情報もローカル側になります。resource-refが無くても束縛します。この形式は非XA用です。
<kohaku-web xmlns="urn:kohaku:web" version="1.0">
<data-source name="jdbc/app">
<url>jdbc:postgresql://db.example.invalid:5432/app</url>
<driver-class>org.postgresql.Driver</driver-class>
<user>app</user>
<password>CHANGE-ME</password>
<max-connections>8</max-connections>
<max-idle>8</max-idle>
<borrow-timeout-millis>30000</borrow-timeout-millis>
<validation-query>SELECT 1</validation-query>
<connection-properties>
<ApplicationName>kohaku-app</ApplicationName>
</connection-properties>
</data-source>
</kohaku-web>password要素は前後の空白も保持します。他の値は原則trimします。接続プロパティは <名前>値</名前> とし、XML要素名にできない名前はJDBC URL側で扱います。標準 web.xml の <data-source> とこのKohaku固有形式は別物です。
接続を借りて返す
javax.sql.DataSource ds = (javax.sql.DataSource)
new javax.naming.InitialContext().lookup("java:comp/env/jdbc/app");
try (java.sql.Connection connection = ds.getConnection();
java.sql.PreparedStatement statement = connection.prepareStatement("SELECT 1");
java.sql.ResultSet result = statement.executeQuery()) {
if (result.next()) {
int value = result.getInt(1);
// value を処理する
}
}Connection・Statement・ResultSetを必ず閉じます。物理接続上限を超える溢れ枠はありません。ドライバ内で止まった接続も枠を保持します。全枠が停滞している場合は待たずに借用を拒否します。borrowTimeoutMillisはgetConnection全体が必ずその時間内に返る保証ではありません。同じトランザクションの二番手の予約待ち、無効接続の破棄、beginRequestやautoCommitの正規化は、ドライバ内で止まってもこの期限で打ち切りません。ドライバ自身の接続・通信期限も設定してください。
UserTransaction
リクエスト内でJNDIから取得し、begin後に借りたプール接続を使い、同じ処理内でcommit/rollbackを完了します。実行中のトランザクションを別スレッドへ任意に持ち出さないでください。
javax.transaction.UserTransaction tx = (javax.transaction.UserTransaction)
new javax.naming.InitialContext().lookup("java:comp/UserTransaction");
tx.setTransactionTimeout(30); // 秒。次のbeginに適用
tx.begin();
// この後でDataSourceから接続を取得し、SQLを実行する。
// 成功時はtx.commit()、失敗時は状態を確認してtx.rollback()。
// どちらの場合もJDBC資源を閉じる。クエリログ
共有定義の queryLog は off が既定です。safe はリテラルを伏せ、hash はハッシュで識別し、unsafe-full はSQL全文を出すモードです。機密値を含むSQLにはunsafe-fullを使わないでください。webapp専用XMLにqueryLog要素はありません。
出力量の設定も conf/resources.yaml に置きます。queryLog.serverRatePerSecond は既定1000、許可範囲1〜10000回/秒。queryLog.poolRatePerSecond は既定200、1以上かつserverRatePerSecond以下です。違反はサーバ起動失敗になります。