エラいハマった話
oracle11gR2に繋ぐ、jdbcのプログラムがあって、接続先のインスタンスが落ちた場合、さて、どうなるでしょう
Class.forName("oracle.jdbc.driver.OracleDriver"); Connection conn = DriverManager.getConnection( "jdbc:oracle:thin:@192.168.xx.xx:1521:db1", "scott", "tiger"); PreparedStatement ps = conn.preparedStatement("select * from TBL where name = ?"); ps.setString(1, "scott"); // この辺でインスタンスが落ちた場合 ps.executeQuery();
で、俺はずっとSQLExceptionが投げられるものだと思っていた。solaris11上の、jvm6で今日動かしたところ、、SQLExceptionが、出ない。
というか、executeQuery()で固まっている?返事が来ない。
まさか、、タイムアウトすら、、しない。。。そんな。。どうやって異常に気づけと言うのだ。。。
デバッグログを追加して、動作を見て、しばらく、呆然としたが、キッチリexecuteQuery()で止まっている。というよりは、実行できるまで頑張りますと、俺のプログラムが言っている。なんて健気な姿なんだ、もういい・・・諦めろ。例外を吐いて早く楽になれ。と、思いながら流れるログを見つめたが無駄だった。
で、これは単に俺が無知だっただけらしい。タイムアウトを設定する方法はある模様。
oracle.jdbc.ReadTimeoutと、oracle.net.CONNECT_TIMEOUTを設定するらしい。
なるほど、とは、思ったが、jndiのように外部で設定できる場合はそれで良いのだろうが、、、色々と探した結果、以下のようなコードになった。ドライバの読み込み前にSystem.setPropertyで入れる。
// ミリ秒単位で指定 System.setProperty("oracle.net.CONNECT_TIMEOUT","10000"); // ミリ秒単位で指定 System.setProperty("oracle.jdbc.ReadTimeout", "10000"); Class.forName("oracle.jdbc.driver.OracleDriver"); (ここから先は同じ)
ただ、上記の例だと10秒に設定しているが、タイムアウトが発生するまで、6分ぐらいかかる。IP unreacheableだから多少遅くなるのは仕方ないとはいえ、豪快に違う。ミリ秒単位で指定する意味ないやん。
参考:
TomcatとOracle間のコネクションプーリングに関するトラブルシューティング