- PR -

JavaTIPS 「データベースに接続したら後始末は確実に」に関して

投稿者投稿内容
やす
会議室デビュー日: 2003/06/05
投稿数: 14
投稿日時: 2006-12-20 10:06
あまりよろしくないコードだと思います。

try {
Connection conn = DriverManager.getConnection("jdbc:odbc:MyTest");
try {
Statement stmt = conn.createStatement();
try {
//
} finally {
stmt.close();
}
} finally {
conn.close();
}
} catch(SQLException e) {System.out.prinlnt(e);}


あのサンプルではこう書くべきではなかったでしょうか?
せめて、nullで初期化しているなら、conn生成時に例外発生した場合
stmtがnullになる可能性があるのでcloseの際のnullチェックだけは
行ってほしかった。
かずくん
ぬし
会議室デビュー日: 2003/01/08
投稿数: 759
お住まい・勤務地: 太陽系第三惑星
投稿日時: 2006-12-20 10:36
私の場合、NullObjectパターンの適用を検討します。

コード:

public class NullConnection implements Connection {
public void close() {
// empty
}
}



nullではなく、このNullObjectで初期化します。
そうすると、nullチェックが無くなり、コードがすっきりーーー

でも正直、高機能なフレームワークを使用して場合は、
中の人がうまくやってくれるだろうから、あまり気にする必要は無いような気がする。

[ メッセージ編集済み 編集者: かずくん 編集日時 2006-12-20 10:38 ]
Gio
ぬし
会議室デビュー日: 2003/11/28
投稿数: 350
お住まい・勤務地: 都内から横浜の間に少量発生中
投稿日時: 2006-12-20 11:12
私ならあまり難しいことは考えずにこう書いてしまいますが。

コード:
Connection conn = null:
Statement stmt = null;
try {
    conn = DriverManager.getConnection("jdbc:odbc:MyTest");
    stmt = conn.createStatement();
    ...

} catch(SQLException e) {
  ...
} finally {
    if (stsm != null) {
        stmt.close();
    }
    if (conn != null) {
        conn.close();
    }
}



リソース利用イディオムの基本ですよね?
平田@IT
会議室デビュー日: 2006/11/21
投稿数: 10
投稿日時: 2006-12-25 20:26
@IT編集部の記事編集を担当しております平田と申します。
いつも@ITをご覧頂き、誠にありがとうございます。

ご指摘頂いた点ですが、全くおっしゃるとおりでしたので、
早急に対応いたしました。

大変お手数ではございますが、訂正した記事をご確認頂ければ幸いです。

http://www.atmarkit.co.jp/fjava/javatips/166java051.html

今後とも@ITをどうぞよろしくお願いいたします。

また、今回のように@IT内の記事でWebページがうまく表示されない、間違いを見つけた、
もしくは記事の内容に疑問がある、こんな記事が読みたい、記事を書いてみたい、
などについては編集部(info@atmarkit.co.jp)までお問い合わせください。
mio
ぬし
会議室デビュー日: 2005/08/25
投稿数: 734
お住まい・勤務地: 神奈川県
投稿日時: 2006-12-25 21:26
んー…。
コード:
} finally {
    if (stmt != null) try { stmt.close(); } catch (SQLException e) {}
    if (conn != null) try { conn.close(); } catch (SQLException e) {}
}


かなー。
nagise
ぬし
会議室デビュー日: 2006/05/19
投稿数: 1141
投稿日時: 2006-12-25 21:49
「例外発生時の後始末を含む正しいプログラムの例」が
引用:

コード:
}
catch(SQLException e){ System.out.println(e); }
finally { // 例外の有無・種類に限らず後続を実行
  try{
    if(stmt != null) // Statementオブジェクトが生成済み?
      stmt.close();  // StatementオブジェクトとJDBCリソースの解放
    if(conn != null) // Connectionオブジェクトが生成済み?
      conn.close();  // Connectionオブジェクト解放,JDBCリソースの解除
  }
  catch(SQLException e){ System.out.println(e); }
}




ですか。これだとstmt.colse()でSQLExceptionが発生するケースで
conn.close()が漏れるんですよね。
例外時の処理フローを正しく理解して「finallyを用いて万全のロジックを」
という趣旨の記事のコードがこれでは笑い話にしかなりませんよ。
ちゃんとソースレビューしてるのでしょうか…。

また、気になった点としてはSQLを処理する場合の例として
SQLExceptionをcatchした部分が省略されている旨を
記述しないのはよくないのではないでしょうか。

メインのSQLExceptionのcatch節ではちゃんと例外処理を記述すべきだけど、
finallyの中のSQLExceptionのcatch節は例外が起きても潰しているんだ、
ということがこの例示から分かるとは思えないので
そのまま真似してSQLExceptionはSystem.out.printlnするというコードが
氾濫しないことを祈るばかりです。
(せめてe.printStackTrace()なら…いやいやいや。そうではなく。)

実務のコードではSQLExceptionは上位にthrowしてまとめて処理することが多いかな。

実際、finally節内で例外が出た場合の挙動を説明しようとした場合、
話が難しくなるのですが、ちゃんと理解しないと例外は潰しちゃいけない
という原則がおざなりになるのではないかと思います。
SQL使用時のfinally節でメインのtry〜finally節での例外を生かすために行う
例外潰しは数少ない例外ですからねぇ。
記事を書く側としては触れたくない話題なのかもしれませんが。
かつのり
ぬし
会議室デビュー日: 2004/03/18
投稿数: 2015
お住まい・勤務地: 札幌
投稿日時: 2006-12-26 07:34
>nagiseさん

確かに上位例外を活かすために後始末処理の例外を握りつぶすのは、
よくあることだと思うのですが、確かに扱いが難しいですよね。

後始末処理なんかで発生した例外の扱いについては、
アプリケーションの設計のポリシーにかかわる部分でもあるので、
一概に何が正しいとは言い切れないとは思いますね。
(うーん、本当に難しいっす)

よくありそうなのがIOExceptionとかSQLExceptionとかですが、
IOExceptionsとかSQLExceptionsみたいな例外クラスをつくって
例外コレクション例外を作ると便利かも。
平田@IT
会議室デビュー日: 2006/11/21
投稿数: 10
投稿日時: 2006-12-26 14:06
@IT編集部の記事編集を担当しております平田と申します。
いつも@ITをご覧頂き、誠にありがとうございます。

ご指摘頂いた点ですが、再度新しいソースコードの
画像を作成し、差し替えさせていただきました。

大変お手数ではございますが、再度訂正した記事をご確認頂ければ幸いです。

http://www.atmarkit.co.jp/fjava/javatips/166java051.html

今後とも@ITをどうぞよろしくお願いいたします。

スキルアップ/キャリアアップ(JOB@IT)