0

私は現在、データベースで多くの作業を行うプロジェクトに取り組んでいます。

コードで何度も何度も再利用した中心的な慣用句の 1 つを次に示します。

私の質問は、getTransformedResults メソッドの各ステップで例外を処理するより良い方法はありますか? これは SQLExceptions を処理する適切な方法ですか、それともこれを行うためのより良い、より簡潔な方法はありますか?

ご意見ありがとうございます。

public ResultType handleResultSet(ResultSet rs);

public ResultType getTransformedResults(String query) throws SQLException {
  ResultType resultObj = new ResultType();

  Connection connection = null;
  try { 
    connection = dataSource.getConnection();
  } catch (SQLException sqle) {
    // cleanup 
    throw sqle;
  }

  Statement stmt = null;
  try { 
    stmt = connection.createStatement();
  } catch (SQLException sqle) {
    try { connection.close() } catch (SQLException dontCare) {}
    // cleanup
    throw sqle;
  }

  ResultSet rs = null;
  try { 
    ResultSet rs = stmtm.executeQuery(query);
    resultObj = handleResultSet(rs);
  } catch (SQLException sqle) {
    // cleanup
    throw sqle;
  } finally {
    if (rs != null) try { rs.close() } catch (SQLException dontCare) {}
    try { stmt.close() } catch (SQLException dontCare) {}
    try { connection.close() } catch (SQLException dontCare) {}
  }

  return resultObj;
}
4

5 に答える 5

1

Java 7には、あなたが評価するかもしれないいくつかの構造があります。私は、catchなしでtry / finalを使用できると思います(これは、catchとrethrowを模倣します)。

また、SQL例外をキャッチして処理したので、おそらくそれを別のものとして(おそらくランタイム例外として)再スローする必要があります。これにより、プライマリエントリポイントですべてのランタイム例外をキャッチするのが簡単になります。 DBにアクセスするたびに例外を処理します。

于 2012-07-12T16:01:26.003 に答える
1

個人的には、サブクラス化するのではなく、インターフェイスの実装を渡すことでこれを処理できます。

最終的に、そのメソッドの例外のみを処理し、メインライン コードを汚染しない場合、他に実際に何ができるでしょうか? また、それを行うポイントは何でしょうか? 各ステップをもう少し細かくすることで、すべてが 1 つの方法になるわけではありませんが、それ以外は...

アプリケーション固有の例外を検討することもできます。これにより、テストと構成がよりクリーンになる可能性がありますが、それは状況によって異なります。


インターフェイスのアイデアの明確化

サブクラス化する代わりに、結果セットの処理とクエリ文字列の取得を実装するインターフェイスを用意することになるため、クエリ用と結果用の 2 つのメソッドを使用します。

現在持っているほとんどのインスタンスに実装を渡しますが、クエリ文字列の代わりにインターフェイスを使用します。コードの残りの部分は本質的に同じですが、インターフェイス impl からクエリ文字列を取得し、インターフェイス impl の結果処理メソッドを呼び出して、クリーンアップまで結果を保存します。

基本的には現在のものと同じですが、匿名クラスやドメイン内の他のクラスを含むインターフェイスを任意のクラスで実装できるため、IMO はよりクリーンです。

于 2012-07-12T16:03:07.083 に答える
0

org.springframework.jdbc.core.JdbcTemplate - 「... JDBC の使用を簡素化し、一般的なエラーを回避するのに役立ちます。」

于 2012-07-12T16:13:07.753 に答える
0

まさにそのような目的を目的としたApache Commons DbUtilsの使用に興味があるかもしれません。

より洗練されたものを使用しようとするといくつかの欠点がありますJDBCが、通常の使用では十分すぎるはずです.

それに加えて、コードに含まれる try/catch ブロックが多すぎるため、次のように簡略化できます。

public interface ResultSetHandler<ResultType> {
     ResultType handleResultSet(ResultSet rs);
}

public <ResultType> ResultType getTransformedResults(String query, ResultSetHandler<ResultType> rsh) throws SQLException {      
  Connection connection = null;
  Statement stmt = null;

  try { 
    connection = dataSource.getConnection();
    stmt = connection.createStatement();
    ResultSet rs = stmtm.executeQuery(query);
    return rsh.handleResultSet(rs);
  } catch (SQLException sqle) {
    // cleanup 
    throw sqle;
  } finally {
    if(stmt != null) {
      statement.close(); // closes also resultSet
      connection.close();
    }
  }
}

ただし、Apache Commons DbUtils ライブラリは内部でまったく同じことを行います。

于 2012-07-12T16:13:18.853 に答える
0
Connection c = null;
Statement s = null;
ResultSet r = null;

try {
  c = datasource.getConnection();
  s = c.createStatement();
  r = s.executeQuery(sql);
  rsh.handleResultSet(r);
}
finally {
  DbUtils.closeQuietly(r);
  DbUtils.closeQuietly(s);
  DbUtils.closeQuietly(c);
}

DbUtils は apache commons-dbutils であり、closeQuietly は次と同等であることに注意してください。

try {
  c.close();
}
catch (SQLException e) {
}

以上のことから、Spring の jdbc 機能を使用することをお勧めします。

JdbcTemplate template = new JdbcTemplate(dataSource);
List data = template.query(sql, new RowMapper() { ... });

RowMapper は、結果セット内の現在の位置をオブジェクトに変換するジョブを実装するインターフェイスです。したがって、1 つの行を処理するロジックを単純に指定するだけで、これら 2 行のコードですべての行のオブジェクトのリストと、行をマップするために必要なものが自動的に収集されます。ResultSet をさまざまな方法で操作できる方法は他にもありますが、これは非常に標準的な方法です。

接続とステートメントの管理はすべて自動的に行われるため、リソース管理について心配する必要はまったくありません。

于 2012-07-12T16:49:36.450 に答える