43

次のコードを検討してください。

PreparedStatement ps = null;
ResultSet rs = null;
try {
  ps = conn.createStatement(myQueryString);
  rs = ps.executeQuery();
  // process the results...
} catch (java.sql.SQLException e) {
  log.error("an error!", e);
  throw new MyAppException("I'm sorry. Your query did not work.");
} finally {
  ps.close();
  rs.close();
}

PreparedStatement.close()と の両方が をResultSet.close()スローするため、上記はコンパイルされませんjava.sql.SQLException。では、finally 句に try/catch ブロックを追加しますか? または、close ステートメントを try 句に移動しますか? それとも、近くに電話することを気にしませんか?

4

13 に答える 13

54

Java 7では、それらを明示的に閉じるのではなく、自動リソース管理を使用して、リソースが閉じられ、例外が適切に処理されるようにします。例外処理は次のように機能します。

tryの例外| クローズの例外| 結果
----------------- + -------------------- + ----------- -----------------------------
      いいえ| いいえ| 通常どおり続行します
      いいえ| はい| close()例外をスローします
      はい| いいえ| tryブロックから例外をスローします
      はい| はい| close()例外をメイン例外に追加します
                 | | 「抑制された」として、主な例外をスローします

うまくいけば、それは理にかなっています。Inは、次のようなきれいなコードを許可します。

private void doEverythingInOneSillyMethod(String key)
  throws MyAppException
{
  try (Connection db = ds.getConnection()) {
    db.setReadOnly(true);
    ...
    try (PreparedStatement ps = db.prepareStatement(...)) {
      ps.setString(1, key);
      ...
      try (ResultSet rs = ps.executeQuery()) {
        ...
      }
    }
  } catch (SQLException ex) {
    throw new MyAppException("Query failed.", ex);
  }
}

Java 7より前は、参照のnullをテストするのではなく、ネストされたfinallyブロックを使用するのが最適です。

私が示す例は、深いネストでは見苦しいかもしれませんが、実際には、適切に設計されたコードは、接続、ステートメント、および結果をすべて同じメソッドで作成することはおそらくありません。多くの場合、ネストの各レベルでは、リソースを別のメソッドに渡し、別のリソースのファクトリとして使用します。このアプローチでは、aからの例外は、ブロックclose()内からの例外をマスクします。tryこれは克服できますが、コードがさらに乱雑になり、Java7に存在する「抑制された」例外チェーンを提供するカスタム例外クラスが必要になります。

Connection db = ds.getConnection();
try {
  PreparedStatement ps = ...;
  try {
    ResultSet rs = ...
    try {
      ...
    }
    finally {
      rs.close();
    }
  } 
  finally {
    ps.close();
  }
} 
finally {
  db.close();
}
于 2008-11-26T19:29:47.680 に答える
29

独自の jdbc を本当に手作業で作成している場合は、間違いなく面倒になります。finally の close() は、独自の try キャッチでラップする必要がありますが、これは少なくとも見苦しいものです。クローズをスキップすることはできませんが、接続がクローズされるとリソースはクリアされます (プールを使用している場合、すぐに終了しない可能性があります)。実際、フレームワーク (休止状態など) を使用してデータベース アクセスを管理する主なセールス ポイントの 1 つは、接続と結果セットの処理を管理して、閉じるのを忘れないようにすることです。

このような単純なことを行うことができます。これにより、少なくとも混乱が隠され、何かを忘れないことが保証されます。

public static void close(ResultSet rs, Statement ps, Connection conn)
{
    if (rs!=null)
    {
        try
        {
            rs.close();

        }
        catch(SQLException e)
        {
            logger.error("The result set cannot be closed.", e);
        }
    }
    if (ps != null)
    {
        try
        {
            ps.close();
        } catch (SQLException e)
        {
            logger.error("The statement cannot be closed.", e);
        }
    }
    if (conn != null)
    {
        try
        {
            conn.close();
        } catch (SQLException e)
        {
            logger.error("The data source connection cannot be closed.", e);
        }
    }

}

その後、

finally {
    close(rs, ps, null); 
}
于 2008-11-26T17:10:40.300 に答える
12

ファイル I/O の場合、通常は try/catch を finally ブロックに追加します。ただし、finally ブロックから例外をスローしないように注意する必要があります。元の例外 (存在する場合) が失われるためです。

データベース接続のクローズのより具体的な例については、この記事を参照してください。

于 2008-11-26T17:09:30.350 に答える
7

また、次の点に注意してください。

"Statement オブジェクトが閉じられると、その現在の ResultSet オブジェクトがあれば、それも閉じられます。"

http://java.sun.com/j2se/1.5.0/docs/api/java/sql/Statement.html#close()

まだ閉じていない場合にのみ、finally で PreparedStatement を閉じるだけで十分です。ただし、本当に細心の注意を払いたい場合は、PreparedStatement を閉じた後ではなく、最初に ResultSet を閉じます (ここでのいくつかの例のように後で閉じると、既に閉じられているため、実際には例外が保証されます)。

于 2009-03-25T15:13:20.490 に答える
7

低レベルの例外管理のコーディングに時間を無駄にしないでください。Spring-JDBC のような高レベルの API を使用するか、接続/ステートメント/rs オブジェクトのカスタム ラッパーを使用して、厄介な try-catch を使用したコードを隠します。

于 2008-11-26T17:20:03.137 に答える
5

私は通常、null 参照で何もしようとしないように注意するなど、このようなものを閉じることができるユーティリティ メソッドを持っています。

通常、 ifclose()が例外をスローしても実際には気にしないので、例外をログに記録して飲み込みますが、別の方法として、RuntimeException. いずれにせよ、多くの場所でこれを行う必要があるかもしれないので、呼び出しやすいユーティリティ メソッドで行うことをお勧めします。

PreparedStatement のクローズが失敗した場合、現在のソリューションは ResultSet をクローズしないことに注意してください。ネストされた finally ブロックを使用することをお勧めします。

于 2008-11-26T17:11:23.543 に答える
4

@ericksonの答えに基づいて、tryこのように1つのブロックで実行してみませんか?

private void doEverythingInOneSillyMethod(String key) throws MyAppException
{
  try (Connection db = ds.getConnection();
       PreparedStatement ps = db.prepareStatement(...)) {

    db.setReadOnly(true);
    ps.setString(1, key);
    ResultSet rs = ps.executeQuery()
    ...
  } catch (SQLException ex) {
    throw new MyAppException("Query failed.", ex);
  }
}

オブジェクトが閉じられると は自動的に閉じられるため、ブロックResultSet内にオブジェクトを作成する必要がないことに注意してください。tryResultSetPreparedStatement

ResultSet オブジェクトは、それを生成した Statement オブジェクトが閉じられるか、再実行されるか、複数の結果のシーケンスから次の結果を取得するために使用されると、自動的に閉じられます。

参照: https://docs.oracle.com/javase/7/docs/api/java/sql/ResultSet.html

于 2017-04-06T17:05:41.500 に答える
3

Java 7 を使用している場合は、AutoCloseable (つまりPreparedStatementResultset)を実装するクラスの例外処理メカニズムの改善を使用できます。

この質問も興味深いかもしれません: Java 7 で ResultSet を閉じる

于 2012-08-06T08:17:14.747 に答える
1

これは古い質問であることは知っていますが、誰かが答えを探している場合に備えて、java には try-with-resouce ソリューションがあります。

static String readFirstLineFromFile(String path) throws IOException {
      try (BufferedReader br =
                   new BufferedReader(new FileReader(path))) {
        return br.readLine();
    }
}
于 2013-06-12T05:02:03.127 に答える
0

close の呼び出しを省略しないでください。問題が発生する可能性があります。

私は try/catch ブロックを finally に追加することを好みます。

于 2008-11-26T17:10:13.653 に答える
0

おそらく古い (シンプルではあるが) やり方ですが、それでも動作します:

public class DatabaseTest {

    private Connection conn;    
    private Statement st;   
    private ResultSet rs;
    private PreparedStatement ps;

    public DatabaseTest() {
        // if needed
    }

    public String getSomethingFromDatabase(...) {
        String something = null;

        // code here

        try {
            // code here

        } catch(SQLException se) {
            se.printStackTrace();

        } finally { // will always execute even after a return statement
            closeDatabaseResources();
        }

        return something;
    }

    private void closeDatabaseResources() {
        try {
            if(conn != null) {
                System.out.println("conn closed");
                conn.close();
            }

            if(st != null) {
                System.out.println("st closed");
                st.close();
            }

            if(rs != null) {
                System.out.println("rs closed");
                rs.close();
            }

            if(ps != null) {
                System.out.println("ps closed");
                ps.close();
            }

        } catch(SQLException se) {
            se.printStackTrace();
        }               
    }
}
于 2014-12-08T05:43:50.140 に答える
-1

フォーカス最終節、

finally {
   try {
      rs.close();
      ps.close();
   } catch (Exception e) {
      // Do something
   }
}

2点修正する必要があると思います。

まず、fainlly 節でもう一度 try & catch を使用します。

次に、ps.close() を実行する前に rs.close() を実行します。

fly1997@naver.com

于 2012-08-06T08:06:38.103 に答える
-2

私はこれを使用します..

finally
{
    if (ps != null) ps.close();
    if (rs != null) rs.close();
}
于 2008-11-26T17:11:00.720 に答える