web-dev-qa-db-ja.com

SQLクエリとJava一定の乱用?

現在、ファイルの先頭にあるJava定数に配置されたフィールド名で記述された多くのコードを引き継ぎ、その後、フィールド名との文字列連結を使用して構築されたSQLクエリを担当しています。 。ファイルの先頭は次のブロックです。

private static final String TABLE_VALID_USER = "valid_user_table";
private static final String TABLE_USER_MANAGEMENT = "V1_USER_MANAGEMENT_TABLE";
private static final String TABLE_ROLE_DEFINITION = "V1_ROLE_DEFINITION_TABLE";
private static final String TABLE_ROLE_MANAGEMENT = "V1_ROLE_MANAGEMENT_TABLE";
private static final String TABLE_USER_STATUS_DEF = "V1_USER_STATUS_DEFNITION";

private static final String COLUMN_NAME_OPEN_ID = "hashed_open_id";

private static final String COLUMN_NAME_INTERNAL_USER_ID = "internal_user_id";
private static final String COLUMN_NAME_USER_ID = "hashed_open_id";
private static final String COLUMN_NAME_USER_NAME = "name";
private static final String COLUMN_NAME_ROLE_ID = "role_id";
private static final String COLUMN_NAME_ROLE_NAME = "role_name";
private static final String COLUMN_NAME_USER_STATUS_CODE = "status_code";
private static final String COLUMN_NAME_USER_STATUS_NAME = "status_name";

private static final String DEFAULT_USER_STATUS = "Pending";

private static final String AS_NAME_COUNT = "cnt";

コードの後半には、文字列の構築でこれらの定数を使用してこのように構築されたSQLクエリがあります。

覚えておく必要があるのは、これらはコード内で非常に離れているため、フィールド名が何であるかを確認するには、常に上下にスクロールする必要があるということです。クエリを読み取ることができるようにするには、多くの精神的な練習が必要です。列がhashed_open_idである可能性があるため、元のプログラマーにとってこれは大した問題ではないことに気付きましたが、そのプログラマーは定数名COLUMN_NAME_USER_IDが完全に受け入れ可能な置き換えであると感じました。良いニュースは、これがユーザーIDであると説明されていることです。

悪い知らせは、データベースの実際の列の名前がhashed_open_idであることは明らかではありません。コードを読むと、この新しい任意の記号COLUMN_NAME_USER_IDがわかります。これは実際にhashed_open_idを意味することを覚えておく必要があり、テーブルのすべての列に対してこれを行う必要があります。それはあなたがコードを読むために学ばなければならないことの量を倍増させるように思われるでしょう。

クエリを理解するには、データベースの知識が必要です。データベースを使用するときは、実際の列名を覚えておく必要があります。 Java定数記号は、SQLデータブラウザーを扱う場合には役立ちません。

String sql = 
    "SELECT "
    + "COUNT(" + COLUMN_NAME_OPEN_ID +") as " + AS_NAME_COUNT + ", " 
    + "FROM "
        + TABLE_VALID_USER + " " 
    + "WHERE "
        + COLUMN_NAME_OPEN_ID + "= ? "
        + ";";

実際のテーブル名と実際の列名を直接使用する方がよいのではないでしょうか。そうした場合、クエリは次のようなコードになります。

    String sql = 
        "SELECT COUNT(hashed_open_id) as cnt, " 
        + "FROM valid_user_table " 
        + "WHERE hashed_open_id= ? ;";

この後者のクエリは、特に実際のテーブル構造がわかっている場合は、明らかに読みやすく、理解しやすくなります。どのテーブル名が操作されているか、どの列が関係しているかを正確に簡単に確認できます。元の状態に戻り、定数の値を調べて、同じ理解を得てください。また、テーブル構造は他のクラスや他のプログラムによって操作されるため、知っておく必要があります。このように、シンボルのリダイレクトの追加レベルとして定数を使用することが有益であると誰かが本当に信じていますか?

理論的には、列名を変更する場合は、1つの場所に移動すると、コード全体に反映されます。ねえ、それはクールですが、どれくらいの頻度でそれをしますか?そして、それはこのクラスを変更するだけです...テーブルを操作する他のクラスとプログラムがあり、いくつかは異なる言語で書かれています。定数を1回変更しても、すべてが変更されることはありません。

読みやすさが重要です。コードを保守するプログラマがコードを読み取り、レビューし、すばやく理解する能力は、列を変更するというまれな利便性よりも重要ではないでしょうか。 10年間存続するコードを検討してください。何人の新しいプログラマーがこのコードを読まなければならないでしょうか?列名は何回変更されますか?

そして、列名をhashed_open_idからstandard_user_idに変更する必要があると想像してみてください。検索と置換を行うのは本当に難しいですか?おそらく、テーブルの作成に使用されるいくつかのSQLスクリプトで同じことを行わなければなりませんでした。定数は、列名の汎用記号ではありません。列名は、列名の汎用記号です。どこでも直接使用しないのはなぜですか?列名のポイントは、列内のデータのシンボルになります。

各列にJava定数を作成するための間接レベルの追加レベルは、それが引き起こす問題の価値があると考える理由はありますか?

6
AgilePro

私はあなたの言うことに同意します。さまざまなプラットフォームで複数の企業で働いたことがあるので、あなたが説明しているような抽象化のレベルを見たことがありません。時折、コードスニペットを記述してSQLスニペットを構築しますが、DB設計用語ではなく、アプリケーションと問題ドメインの用語で説明します。例えば
where-cluase-for-employee = "<several lines of SQL>"
一方
where-clause-for-contractor="<a different complex predicate>"

SQLはプログラミング言語です。 Javaメソッド呼び出しを文字列として作成し、それを実行することがベストプラクティスであると考える人は誰もいません。SQLでこれを行うのはなぜですか?

保守性と変更の容易さも重要です。コードは、今まで見たことがない、午前3時に修正しなければならない不運なオンコール担当者を考慮して記述されるべきだと思います。どうしてもコードを効率的でコンパクトにするが、それを理解できるのは作者だけではない。

Javaからテーブル名と列名を抽象化し、SQLをコンパクトブロックとして保持する別のアプローチがあります。また、アプリケーションのワークロードに応じて、ランタイムを改善できます。SQLを格納された手順。良いSP命名規則は、それが何をするかを正確に示します(read_count_by_user(質問の例の場合)、アプリケーションとSQLの間の規約が定義されています。返される列が変更された場合、アプリケーションも変更する必要がありますが、これは現在直面している問題です。影響分析は、ソースコードのテキスト検索です。モジュール性が向上します。チューニングと書き換えは、手順ごとに行うことができます。

開発者の唯一の不満がDBの命名規則にある場合は、テーブルと列の開発者にわかりやすい名前で一連のビューを定義するように依頼してください。示されている単純な使用例では、これらはパフォーマンスに影響を与えません。

1
Michael Green

IMOはその実践エンドユーザー向けのグラフィカルなポイントアンドクリックのアドホッククエリビルダーを作成しようとした場合にのみ意味があります、その場合でも、JDBCメタデータを使用してプルします列名を出力します。

それ以外の場合は、実用的な利点はなく、欠点のみがわかります。

0

回答:おそらくテンプレートコード用で、コピーしてカスタマイズするのは100倍に。

リファクタリングには注意が必要です。コードを少し良くするためのリファクタリングは、多くの場合、効果がありません。より根本的なリファクタリングはより優れています。

ここで:定数(自動化可能)を入力するだけで、特に手動で作業を行うだけです。

古い状態は悪いです、そして私の推測では、コードはコピーされたクエリからコピーされたものであり、コピーされたコードです。コードコピーを確認するのに最適なタイミングです。これらは、リファクタリング後は簡単には見つかりません。リピートユアセルフは適用できませんか?コードはどのようにして生成されたキーをフェッチしますか?

物事を改善できるかどうか、リソースの試用版、JPA、おそらくSQLを宣言型データなどとして使用できるかどうかを確認する良い機会です。

また、この種のリファクタリングをビジネスロジックの変更と混在させないでください。手動で列名を置き換えると、間違った列が置き換えられた場合にどれほど不快になるかを考えてください。新しいコードのデバッグに優れています。

0
Joop Eggen