2

JDBC PreparedStatements を使用してデータベースにアクセスするアプリケーションがあります。データ アクセスを一般的なものにするために、データベースにアクセスするメソッドは PreparedStatement setObject メソッドを多用します (同様のアプローチについて説明している質問を参照してください)。説明する擬似コード:

public ResultSet getResultSet(String sql, List<Object> parameters) throws SQLException {

  PreparedStatement preparedStatement = db.getConnection().prepareStatement(sql);

  for(int i = 0; i < parameters.size(); i++) {
    preparedStatement.setObject(i+1, parameters.get(i));
  }

  return preparedStatement.executeQuery();
}

getResultSet(String, List) を使用してさまざまなクエリを実行できるため、これによりコードの重複が減少します。ただし、実行時に SQLExceptions がスローされるリスクもあります。状況例:

  1. 誰かが getResultSet("SELECT columnWithVarchar2Type FROM someTable WHERE columnWithVarchar2Type = ?", Arrays.asList(someCustomObject)); を呼び出します。
  2. db.getConnection().prepareStatement(sql) はOraclePreparedStatementを返します
  3. PreparedStatement.setObject が java.sql.SQLException 'Invalid column type' をスローする

OraclePreparedStatement の動作はおそらく正当化されます。someCustomObject を columnWithVarchar2Type にマップする方法がわかりません。しかし、getResultSet(String, List) の呼び出し元にとっては、これは驚くべきことです。結局のところ、呼び出し元は、要求されたとおりに、オブジェクトを含むリストを提供したのです!

質問は次のとおりです: PreparedStatement の実装間の違いを考えると、呼び出し元が実行時に SQLExceptions をスローするパラメーターを渡すことを防ぐために、getResultSet メソッドの署名にコンパイル時の安全性を導入する方法はありますか?

もちろん、完全なコンパイル時の安全性は不可能ですが、ジェネリックなどを使用して、渡された SQL とは無関係に常にSQLException が発生するパラメーターを誰かが渡すのを防ぐ方法はありますか?

編集: これはおそらく理論的には不可能です (誰かが PreparedStatement を実装し、決して SQLExceptions をスローしないか、常に setObject() から SQLExceptions をスローすることを決定することを妨げるものは何もありません)。ただし、ORM がこの問題をどのように回避するかを知っておくとよいでしょう。

4

0 に答える 0