エラいハマった話

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間のコネクションプーリングに関するトラブルシューティング