4

これは別の議論のテーマですが、今回は単純で文書化された回答のみを探しています. シナリオ:

次の方法を想定しましょう。

 public static Hashtable<Long, Dog> getSomeDogs(String colName, String colValue) {
  Hashtable<Long, Dog> result = new Hashtable<Long, Dog>();
  StringBuffer sql = null;
  Dog dog = null;
  ResultSet rs = null;
      try {
          sql = new StringBuffer();
          sql.append("SELECT * FROM ").append("dogs_table");
          sql.append(" WHERE ").append(colName).append("='");
          sql.append(colValue).append("'");
          rs = executeQuery(sql.toString());
              while (rs.next()) {
                  dog= new Dog();
                  //...initialize the dog from the current resultSet row
              result.put(new Long(dog.getId()), dog);
              }
          }
     catch (Exception e) {
         createErrorMsg(e);
         result = null; //i wonder....
         }
     finally {
         closeResultSet(rs); //this method tests for null rs and other stuff when closing the rs.
     }
   return result;
 }

質問:

1. いくつかの属性を持つ犬を返すこのテクニックを改善するために、どのような方法を提案しますか?

2. rs.next() は、null ResultSet に対して false を返すか、次のような例外を生成します。

文字列 str = null; System.out.println(str.toString());

3. ResultSet の現在の行から犬のオブジェクトを初期化しているときに、接続障害、互換性のない値が犬のプロパティ セッターに渡されたなどのような問題が発生した場合はどうなりますか? ハッシュテーブルには今では 10 個の要素があるかもしれませんし、何もないかもしれません (最初の行)。次のアクションは次のとおりです。a) null ハッシュテーブルを返します。b) この段階での結果のハッシュテーブルを返します。c) 例外をスローする: ここでの例外の種類は何ですか?

4. この点については、全員が同意すると思います。悪いことは何も起こらず、尋問に行がなく、null 値が返されます。ただし、@Thorbjørn Ravn Andersen はここで、null 値ではなく NullObject を返す必要があると述べています。あれは何だろう。

5. アプリケーションをいくつかのレイヤーまたはレベルに分割する必要があると言っている人やグループに気づきました。上記の例を考えると、私が考えることができるこれらのものを除いて、ここにはどのようなレイヤーがありますか:

Layer1 :: アクションが実行されるデータベース層: このメソッド。

レイヤー2 :: ??? : 新しい Dog オブジェクトが構築されるレイヤー: 私の Dog オブジェクト。

レイヤー3 :: ? : 犬のコレクションで何かをしようとしているレイヤー: GUI レイヤー、主に、またはユーザー インターフェイスのサブレイヤー。

申請の流れをたどると、1層目で例外が発生した場合、どのように対処するのがベストでしょうか? 私の考え: 例外をキャッチし、例外をログに記録し、何らかの値を返します。それはベストプラクティスですか?

マニーさん、ご回答ありがとうございます。他の人がこれらの問題についてどう思うか楽しみにしています。

4

6 に答える 6

8

以下は避けたい

   sql.append("SELECT * FROM ").append("dogs_table");
   sql.append(" WHERE ").append(colName).append("='");
                        sql.append(colValue).append("'");

代わりに、関連するパラメーター セッター メソッド ( ) などでPreparedStatementを使用します。これにより、引用符を持つことによる値の問題や、SQL インジェクション攻撃 (または、より一般的には、SQL 構文の形成) を防ぐことができます。setString()colValuecolValue

コレクションが単に空の場合、null を返すことはありません。これは非常に直感に反しているように見え、クライアントの観点からは完全に予想外です。

エラー状態で null を返すことはお勧めしません。これは、クライアントが明示的にこれを確認する必要があるためです (おそらく忘れるでしょう)。必要に応じて空のコレクションを返すか (これは null オブジェクトに関するコメントに似ている可能性があります)、例外をスローする可能性が高くなります (状況と重大度に応じて)。例外は、発生したエラーに関連する情報を保持するという点で便利です。Null は何も教えてくれません。

Dogオブジェクトの構築中に問題が発生した場合はどうすればよいですか? それは、アプリケーションの堅牢性と回復力に依存すると思います。のサブセットを返すのは問題ですDogか、それとも完全に壊滅的であり、これを報告する必要がありますか? これはアプリケーションの要件です (これまでは、ベスト エフォートまたはオール オア ナッシングのいずれかのシナリオに対応する必要がありました)。

いくつかの観察。私は古いものではなくHashMapHashtableを使用します (すべてのアクセスに対して同期され、さらに重要なことに、適切ではありませんCollection- がある場合は、任意Collectionの を期待する他のメソッドに渡すことができます)、およびStringBuilderを同様の理由で使用します。大きな問題ではありませんが、知っておく価値があります。 CollectionStringBuffer

于 2009-10-09T16:59:55.173 に答える
6

あなたは5つの質問をします

1. いくつかの属性を持つ犬を返すこのテクニックを改善するために、どのような方法を提案しますか?

実際にはいくつか。

  • メソッドは静的です-これはひどいことではありませんが、別の静的な「executeQuery」を使用することになり、シングルトンのにおいがします...
  • クラス「Dogs」は、オブジェクト指向の命名規則に違反しています。複数形の名詞は、クラスの 1 つのインスタンスが物のコレクションを保持しない限り、適切なクラス名にはなりません。また、Dogs は実際には「Dog」であるように見えます。
  • HashTableはほとんど非推奨です。HashMap または ConcurrentHashMap を使用すると、パフォーマンスが向上します。
  • 複数の追加を使用してクエリの最初の部分を作成する理由がわかりません。悪くはありませんが、実際よりも読みにくいので、 sql.append ("SELECT * FROM dogs_table WHERE "); とにかく、選択した列 (*) とテーブル名 (dogs_table) をハードコードするだけなら、より賢明な開始になります。

2. rs.next() は null ResultSet に対して false を返すか、例外を生成します

これは問題ではないようですが、はい、処理する行がなくなるとすぐに rs.next() は false を返します。

3. ResultSet の現在の行から犬オブジェクトを初期化しているときに、何か問題が発生した場合

「何か悪いことが起こった」場合、次に何をするかはあなたとあなたのデザイン次第です。寛容なアプローチ (可能な限りすべての行を返す) と、寛容でないアプローチ (例外をスローする) があります。私は「容赦ない」アプローチに傾倒する傾向があります。「寛容な」アプローチでは、存在するすべての行が返されていないことをユーザーが認識できないためです。エラーの前に取得したすべての行のみが返されます。しかし、寛容なアプローチの場合もあります。

4. この点については、全員が同意すると思います。悪いことは何も起こらず、尋問に行がなく、null 値が返されます。

これは、明確な正解があるものではありません。まず、書かれているようにメソッドで起こっていることではありません。空の HashTable を返します (これが「null オブジェクト」の意味です)。第 2 に、「結果が見つからない」場合、null が常に答えになるとは限りません。

null を見たことがありますが、代わりに空の結果変数も見ました。どちらも正しいアプローチであると主張しますが、空の結果変数を好みます。ただし、一貫性を維持することが常に最善であるため、「結果なし」を返す方法を選択し、それをそのまま使用してください。

5. アプリケーションをいくつかのレイヤーまたはレベルに分割する必要があると言っている人やグループに気づきました。

これは、アプリケーションの残りの部分を見ずに、他のものよりも答えるのが難しいです。

于 2009-10-09T19:44:32.283 に答える
4

Null オブジェクト パターンは、コード内の NPE:s および null チェックを回避するために、常にオブジェクトを返す設計パターンです。あなたの場合、これは を返す代わりに、代わりにnull空を返すことを意味しますHashtable<Long, Dogs>

その理由は、これはコレクションであり、他のコードがそのようにアクセスするため、空のコレクションを返しても壊れないからです。繰り返されず、驚くべきものは何も含まれず、NPE:s がスローされるなどの原因にもなりません。

正確に言えば、Null オブジェクトはクラス/インターフェースの特別な実装であり、まったく何もしないため、いかなる種類の副作用もありません。使用しないという性質により、メソッド内で何が起こってもnullメソッド呼び出しから常にオブジェクトを取得することがわかっている場合は、null をチェックしたりコードを作成したりする必要さえないため、コードがよりクリーンになります。それらに反応します!Null Object は何もしないので、シングルトンとして置いておくこともできるので、そうすることでメモリを節約できます。

于 2009-10-09T17:10:02.173 に答える
3

次のように、文字列を連結して SQL クエリを作成しないでください。

sql = new StringBuffer();
sql.append("SELECT * FROM ").append("dogs_table");
sql.append(" WHERE ").append(colName).append("='");
sql.append(colValue).append("'");

これにより、よく知られているセキュリティ攻撃であるSQL インジェクションに対してコードが脆弱になります。これを行う代わりに、 a を使用し、適切なメソッドをPreparedStatement呼び出してパラメーターを設定します。これを使用して列の値set...()を設定することしかできないことに注意してください。これを使用して列を動的に構築することはできません。例:

PreparedStatement ps = connection.prepareStatement("SELECT * FROM dogs_table WHERE MYCOL=?");
ps.setString(1, colValue);

rs = ps.executeQuery();

を使用する場合、JDBC ドライバーは、SQL インジェクション攻撃が機能しないように、PreparedStatementに存在する可能性のある特定の文字を自動的にエスケープします。colValue

于 2009-10-09T19:53:15.553 に答える
2

エラーが発生した場合は、例外をスローします。データがない場合は、null ではなく空のコレクションを返します。(また、一般的に、特定の実装ではなく、より一般的な「マップ」を返す必要があります)、

于 2009-10-09T17:16:53.390 に答える
0

単純な古い JDBC の代わりにSpring-JDBCを使用することで、ボイラープレート JDBC コードの量を大幅に削減できます。これは、Spring-JDBC を使用して書き直された同じメソッドです。

public static Hashtable<Long, Dogs> getSomeDogs(String colName, String colValue) {

    StringBuffer sql = new StringBuffer();
    sql.append("SELECT * FROM ").append("dogs_table");
    sql.append(" WHERE ").append(colName).append("='");
    sql.append(colValue).append("'");

    Hashtable<Long, Dogs> result = new Hashtable<Long, Dogs>();

    RowMapper mapper = new RowMapper() {

        public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
            Dogs dog = new Dogs();
            //...initialize the dog from the current resultSet row
            result.put(new Long(dog.getId()), dog);
        }
    };
    (Hashtable<Long, Dogs>) jdbcTemplate.queryForObject(sql, mapper);
}

Spring は以下を処理します。

  1. ResultSet の反復処理
  2. ResultSet を閉じる
  3. 一貫した例外処理

他の人が言及しているように、文字列 (または StringBuffer) の代わりに PreparedStatement を使用して SQL を構築する必要があります。何らかの理由でこれができない場合は、代わりに次のように SQL を作成することで、クエリの読みやすさを向上させることができます。

    String sql = 
        "SELECT * FROM dogs_table " +
        "WHERE " + "colName" + " = '" + colValue + "'";
于 2009-10-09T17:55:08.677 に答える