例外トラップではまる

数日前より調査していた障害がようやく片付いた。
今回はまった原因は例外発生時トラップ(例外の内容表示)に不備があり、
本質の原因が見えていなかったことである。

現在主に使用している言語はJavaであるが、データベースから検索を行う処理で、
自分は以下のようなコーディングをしている。
(しかも、後輩にもこう書くよう指導してきた)


PreparedStatement st = conn.prepareStatement(sql);
try {
...
ResultSet rs = st.executeQuery();
try {
while (rs.next()) {
...
ループ内処理
...
}
} finally {
rs.close();
}
} finally {
st.close();
}

つまりは、

  • リソースの確保直後に "try" を記述
  • リソースが不要になったタイミングで、finally 節の中で後処理を行う

ということで、ルールも簡単で他の人へ指示しても取り違えることは少ないし、
リソースのクローズは確実に行われるし、例外内容の表示方法は呼び出し側に
任されるので、我ながら「完璧だ!」と思っていた。

今回問題となったのは、上記の「ループ内処理」の中で、データベースの状態を
おかしくするようなことをしてしまった場合、finally節の中の close() でも
例外が発生し、もともと起こっていた例外が隠されてしまっていた。

そんなわけで本質の障害を発見することができず、3日も費やしてしまったのでした...

こんなケースでは、どう書けばいいんだろう?
今回は、以下のような対処をしました。


PreparedStatement st = conn.prepareStatement(sql);
try {
...
ResultSet rs = st.executeQuery();
try {
while (rs.next()) {
...
ループ内処理
...
}
} catch (Exception e) {
ログ出力(e);
throw e;
} finally {
ComFunc.safeClose(rs);
}
} catch (Exception e) {
ログ出力(e);
throw e;
} finally {
ComFunc.safeClose(st);
}

ちなみに、safeClose()は共通関数として作成した、クローズ時に例外が
発生しても外に投げない(ログは出力)関数です。

でも、なんか美しくないなぁ...