2025/10/28 WebサーバがTomcat9、データベースがAmazon RDS for Oracle19cで構成された社内システムの、 Oracleセッションの妥当性の総合テストをしたいです。 この構成でOracleセッションの妥当性といった場合、 アプリケーションから見ると接続プーリングの妥当性を試験することと同じ意味ですか。 ------ 概ね同じだと思って良い。ただし前者の方が少し広いイメージ。 ------ 接続プール健全性 DB再起動耐性 長時間稼働テスト 同時接続テスト=負荷テスト 文字コード整合性 ------ 接続プール健全性や同時接続テストは、Apache JMeterを使用した負荷テストの結果としても検証できるか? ⇒アプリケーション階層に限ればYES。 一例で、 同時接続数 応答時間 エラーが無い事 長時間実行しても性能悪化がない事 は、接続プールの設定が健全であることを示唆する。 一方、 ・DB再起動耐性…Web稼働中にDBが再起動しても正常に再接続できること ・接続リークの有無 ・プールの使用率、有効に使えているか、余剰がないか⇒JMeterでは計測できない ・validation queryの設定の妥当性 はJMeterの負荷テストでは分からない。 ------ 接続リークの有無は、Oracle側のV$SESSIONにSTATUS=INACTIVEのセッションが残り続けていないかを見れば確認できますか? ------ それだけで即断定はできないが、LAST_CALL_ETが大きいセッションがあればリークの疑いがある。 逆に言えば、そのようなセッションがなければリークもないことが示唆される。 ------ validation queryの設定が妥当かは、どのようにして確認できますか? ------ SELECT SQL_TEXT, EXECUTIONS, LAST_ACTIVE_TIME FROM V$SQL WHERE SQL_TEXT LIKE 'SELECT 1 FROM DUAL%' ORDER BY LAST_ACTIVE_TIME DESC; ------ またはHikariCPのログを見る ------ HikariPool-1 - Connection is not valid, will be tested again. HikariPool-1 - Added connection conn12345. ------ HikariCPではなく、TomcatのDBCPの場合、validation queryという概念は有りますか?そうならどこで定義できますか? ------ はい。xmlで定義できる。 validationQuery="SELECT 1 FROM DUAL" ------ maxActive="20" maxIdle="10" minIdle="5" validationQuery="SELECT 1 FROM DUAL" testOnBorrow="true" testWhileIdle="true" timeBetweenEvictionRunsMillis="60000" validationInterval="30000" ------ validationQuery=を省略した場合のデフォルトの動作は? 「接続の妥当性チェックは実行されない」というのが基本動作です。 ただし、Tomcat9が使用するDBCP2は、 JDBC 4 対応ドライバであれば Connection.isValid(timeout) を使用して検証する。 Oracle JDBC 11g 以降のドライバは Connection.isValid() を実装しています。 したがって、Tomcat9+Oracle19c(JDBC 4.0 対応)では、 validationQuery を省略しても isValid() による接続確認は実行されます。 ただし、この動作は ドライバ依存 です。 もし isValid() が内部で「常に true を返すだけ」のような実装であれば、 壊れた接続を検知できない可能性もあります。 ------ お勧め設定 ------ ------ Connection.isValid(timeout) を使用して検証した場合、OracleのV$SQLで確認する方法は使えますか? ------ できない。運用や監視で「検証SQLが実際に発行されていることを確認したい」場合、 validationQuery="SELECT 1 FROM DUAL" を明示的に設定する のが確実です。 ------ testOnBorrow="false"の場合、Tomcat稼働中にOracleがダウンして再起動した場合、 接続プーリングがエラーを起こす可能性がありますか? ------ はい。このようなエラーが出る可能性がある。 java.sql.SQLRecoverableException: No more data to read from socket ORA-03113: end-of-file on communication channel ORA-01012: not logged on ------ もし、データベースのダウンと再起動を検知した場合はTomcatも再起動する運用手順を徹底するならば、 接続プーリングがダウンの前後でエラーなく再接続できるかの試験は不要でも良いですか? ------ はい。その場合は代わりに再起動運用作業の運用テストを重点的に行うことになる。 ------ テスト用サンプルプログラム ------ import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; import java.sql.Connection; import java.sql.ResultSet; import java.sql.Statement; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class OracleConnectionPoolTest { private static final String JDBC_URL = "jdbc:oracle:thin:@your-rds-endpoint:1521/ORCL"; private static final String USER = "your_username"; private static final String PASSWORD = "your_password"; // スレッド数(同時接続数のテスト) private static final int THREAD_COUNT = 10; // テスト繰り返し回数 private static final int TEST_ROUNDS = 100; public static void main(String[] args) { // HikariCP設定 HikariConfig config = new HikariConfig(); config.setJdbcUrl(JDBC_URL); config.setUsername(USER); config.setPassword(PASSWORD); // プール設定(必要に応じて調整) config.setMaximumPoolSize(10); config.setMinimumIdle(2); config.setConnectionTimeout(5000); // 接続取得タイムアウト(ms) config.setIdleTimeout(300000); // アイドル接続の保持時間(ms) config.setValidationTimeout(2000); config.setConnectionTestQuery("SELECT 1 FROM DUAL"); config.setLeakDetectionThreshold(10000); // 接続リーク検出(ms) config.setInitializationFailTimeout(-1); // DB接続が無くても起動継続 // DataSource生成 try (HikariDataSource dataSource = new HikariDataSource(config)) { System.out.println("=== Oracle Connection Pool Test Started ==="); ExecutorService executor = Executors.newFixedThreadPool(THREAD_COUNT); for (int i = 0; i < THREAD_COUNT; i++) { final int threadId = i; executor.submit(() -> { for (int round = 1; round <= TEST_ROUNDS; round++) { try (Connection conn = dataSource.getConnection(); Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery("SELECT SYSDATE FROM DUAL")) { if (rs.next()) { System.out.printf("Thread-%02d Round-%03d OK: %s%n", threadId, round, rs.getString(1)); } // ランダムな短い待機(疑似負荷) Thread.sleep((long) (Math.random() * 500)); } catch (Exception e) { System.err.printf("Thread-%02d Round-%03d ERROR: %s%n", threadId, round, e.getMessage()); } } }); } executor.shutdown(); while (!executor.isTerminated()) { Thread.sleep(1000); } System.out.println("=== Oracle Connection Pool Test Completed ==="); } catch (Exception e) { e.printStackTrace(); } } } ------ private static final String JDBC_URL = "jdbc:oracle:thin:@your-rds-endpoint:1521/ORCL"; private static final String USER = "your_username"; private static final String PASSWORD = "your_password"; ------ javac -cp .:hikaricp-5.0.1.jar:ojdbc8.jar OracleConnectionPoolTest.java java -cp .:hikaricp-5.0.1.jar:ojdbc8.jar OracleConnectionPoolTest ------