2

次のようなメソッドがあります。

try {
  doStuff();
} catch (Exception ex) {
  logger.error(ex);
}

(私は実際には doStuff のようなメソッド名を使用しません - これは単に物事を簡単にするためです)

doStuff ではさまざまなことを行いますが、その中には、次で終わるデータ アクセス メソッド (つまり、doStuff 内の別のメソッド) の呼び出しがあります。

} catch (SQLException ex) {
  logger.error(ex);
} finally {
  try {
    connection.close();
    proc.close();
    results.close();
  } catch (Exception e) {
    logger.error(e);
  } //<--Exception thrown here. HUH?
}
return stuff;

このコードをステップ実行すると、最後から 2 番目の中括弧 (コメントでマーク) に到達し、NullPointer 例外を含む最初のコード ブロックのキャッチにジャンプします。はそのresults.close()直前に実行されているものです (結果は null ではありません)。私の IDE (NetBeans) は、スタック トレース (スタック トレースが null であることを示しています) または例外の名前以外のその他の情報 (私が知る限り) を提供しません。

このコードは、以前は正常に実行されていました。実際、実行中に、データ アクセス メソッド (この例外が発生している場所) が呼び出していたストアド プロシージャを変更すると、このエラーが発生し始めました (アプリケーションはまったく停止されませんでした)。その後、再構築と再起動を試みましたが、役に立ちませんでした。sproc を元に戻すことはできますが、コードのどこで例外が発生しているかを考えると、sproc がこのエラーの一部であっても意味がないため、このエラーの原因を突き止めたいと思います。

4

6 に答える 6

3

取得した逆の順序でリソースを閉じます。

try 
{ 
    results.close(); 
    proc.close(); 
    connection.close(); 
} 
catch (Exception e) 
{ 
    logger.error(e); 
} //<--Exception thrown here. HUH? 

次のような方法もお勧めします。

public class DatabaseUtils
{
    // similar for ResultSet and Statement
    public static void close(Connection c)
    {
       try
       {
           if (c != null)
           {
               c.close();
           }
       }
       catch (SQLException e)
       {
           // log or print.
       }
    }
}
于 2010-02-18T18:45:51.507 に答える
3

doStuff() メソッドが SQLException 以外のものをスローしており、キャッチされていません。catch(Exception e) ブロックを追加し、その例外をログに記録して、何が起こるかを確認します。

このコード サンプルは、説明しているのと同じ動作を示します。

public class TryCatchTest {
    public static void main(String[] args) {
        try {
            System.out.println("foo");
            throw new NullPointerException();
        } finally {
            try {
                System.out.println("bar");
            } catch (Exception e) {
                e.printStackTrace();
            }
        } // exception thrown here
    }
}
于 2010-02-18T18:53:56.607 に答える
2

NullPointerException は、ステートメントのない行ではスローできません。

実行しているクラス ファイルが、表示するソースと同じバージョンであることを確認します (誤って構成されたクラスパスにクラスが 2 回含まれていて、古いバージョンがクラスパスで最初に見つかった場合、または再コンパイルされたクラス ファイルがテストに使用した Web コンテナーに正しくコピーされていません)。

編集: emh が指摘するように、finally ブロックに入る前に例外が発生した可能性もあります。

于 2010-02-18T18:46:28.597 に答える
2

ロガーが null である可能性があります。

特定が難しい例外は、多くの場合、例外ハンドラー自体でスローされます。

于 2010-02-18T18:39:40.330 に答える
0

これは JDBC ドライバーで発生していると 99% 確信しています。まず、あなたの close ステートメントは逆です。結果セット、ステートメント、および接続をこの順序で閉じる必要があります。

トランザクションを管理しているアプリケーション サーバーで実行している場合、トランザクションをコミットしようとすると、JDBC ドライバー内で例外が発生する可能性があります。

また、保存された手順で結果セットがどのように生成されるかについても考えられます。たとえば、ある手順にアクセスしてから別の手順にアクセスし、最初の手順に戻って参照するなどです。

于 2010-02-18T18:54:06.177 に答える
0

コメントで述べたように、処理したくない例外をキャッチしないでください。あなたのコードでは、それが完全であると仮定すると、例外で興味深いことを何もしていないため、例外が発生した場所と理由について混乱を引き起こしています。printStackTrace()ドメイン固有の例外 (your.package.DataAccessException など) でラップするなど、本当に log または よりも多くのことをしたい場合は、素晴らしいことです。

次のようにします。


ResultSet results = null;
CallableStatement proc = null;
Connection connection = null;
try {
  connection = >
  proc = connection.createCallableStatement(..);
  results = proc.execute(..);
  >
} finally {
  try {
    if ( results != null ) {
      results.close();
    }
  } catch (Exception e) {
    logger.error(e);
  }
  try {
    if ( proc != null ) {
      proc.close();
    }
  } catch (Exception e) {
    logger.error(e);
  }
  try {
    if ( connection != null ) {
      connection.close();
    }
  } catch (Exception e) {
    logger.error(e);
  }
}

そして、呼び出し元で:


    try {
        doStuff();
    } catch ( SQLException e ) {
        throw new your.package.DataAccessException(e);
        // or just let the SQLException propagate upward
    } catch ( Exception e ) {
        throw new your.package.AppException("omg, crazy pills!", e);
        // or, once again, just let the exception
        //  propagate and don't catch anything
    }

だから、持ち帰り:

  1. 発生した例外をログに記録せず、別の例外にネストして渡します。SQL アクションが成功したかどうかをプロセスに知らせたくありません。やめて別のことをしたほうがいいでしょう。
  2. 行の終わりまで例外を入れ子にします。そうすれば、サーバー ログ全体に散在する 5 つの場所ではなく、例外を処理したい場所に完全なトレースが常に表示されます。
  3. ネストされた例外 (はい、2 回言いました!) により、JVM が実際にどこから例外をスローしたかを気にせず、次の例外を追跡して、それが実際には呼び出し可能なステートメントであったか、リソースの不適切なクローズであったことを伝えます。など
  4. コードでキャッチされたエラーから例外をネストしてスローしないでください。finally元の例外に干渉し、クローズの失敗や最初に開かれなかったステートメントよりも興味深いものになります。
  5. 変数を使用する前に変数を設定し、変数をnull使用する前に null をチェックしますclose()
  6. ブロック内の各問題を個別にキャッチしfinallyます。ブロックを閉じることができない可能性があるResultSetためです (実行エラーが原因で最初に開かないため)。ただし、CallableStatementandConnectionはおそらく影響を受けず、それでもリソースをリークさせます。

それが役立つことを願っています。

于 2010-02-18T19:23:58.340 に答える