web-dev-qa-db-ja.com

JPAおよびHibernate-基準とJPQLまたはHQL

Criteria または HQL を使用することの長所と短所は何ですか? Criteria APIは、Hibernateでクエリを表現するためのNiceオブジェクト指向の方法ですが、Criteria QueryはHQLよりも理解/構築が難しい場合があります。

いつCriteriaを使用し、いつHQLを使用しますか?どのユースケースで何を好みますか?それとも、単に好みの問題ですか?

283
cretzel

私は、動的なクエリに基準クエリを最も好んでいます。たとえば、パラメータに応じて、いくつかの順序を動的に追加したり、一部の部分(制限など)を残したりする方がはるかに簡単です。

一方、静的で複雑なクエリにはHQLを使用しています。HQLの理解と読み取りがはるかに簡単だからです。また、HQLはもう少し強力です。さまざまな結合タイプ用。

205
cretzel

HQLとcriteriaQueryにはパフォーマンスの点で違いがあります。criteriaQueryを使用してクエリを起動するたびに、DBの最後にクエリされたキャッシュに反映されないテーブル名の新しいエイリアスが作成されます。これにより、生成されたSQLをコンパイルするオーバーヘッドが発生し、実行に時間がかかります。

フェッチ戦略について [http://www.hibernate.org/315.html]

  • 基準は、マッピングの遅延設定を尊重し、ロードするものがロードされることを保証します。これは、1つのCriteriaクエリが、すべての非遅延マップアソシエーションとコレクションを含むサブグラフをフェッチするためのいくつかのSQL即時SELECTステートメントをもたらす可能性があることを意味します。 「方法」、さらには「何」を変更する場合は、setFetchMode()を使用して、特定のコレクションまたは関連付けの外部結合フェッチを有効または無効にします。基準クエリは、フェッチ戦略(結合vs選択vs副選択)も完全に尊重します。
  • HQLは、マッピングの遅延設定を尊重し、ロードするものが確実にロードされるようにします。これは、1つのHQLクエリが、すべての非遅延マップアソシエーションおよびコレクションを含むサブグラフをフェッチするためのいくつかのSQL即時SELECTステートメントをもたらす可能性があることを意味します。 「方法」や「対象」さえも変更したい場合は、LEFT JOIN FETCHを使用して、特定のコレクションまたはNULL入力可能な多対1または1対1の関連付けの外部結合フェッチを有効にするか、JOIN FETCHを有効にしますNULL不可の多対1または1対1の関連付けの内部結合フェッチ。 HQLクエリは、マッピングドキュメントで定義されたfetch = "join"を尊重しません。
90
Varun Mehta

基準はオブジェクト指向のAPIですが、HQLは文字列の連結を意味します。つまり、オブジェクト指向のすべての利点が適用されます。

  1. 他のすべてが等しい場合、OOバージョンは多少エラーが発生しにくくなります。有効なCriteriaオブジェクトのみがCriteriaツリーを作成できますが、古い文字列はHQLクエリに追加できます。事実上、Criteriaクラスはより制約されています。
  2. オートコンプリートを使用すると、OOがより発見しやすくなります(したがって、少なくとも私にとっては使いやすくなります)。クエリのどの部分がどこに行くのかを必ずしも覚えておく必要はありません。 IDEはあなたを助けることができます
  3. また、構文の詳細を覚える必要もありません(どのシンボルがどこに行くかなど)。知っておく必要があるのは、メソッドを呼び出してオブジェクトを作成する方法だけです。

HQLはSQLに非常によく似ているので(ほとんどの開発者はすでによく知っています)、これらの「覚えておく必要がない」引数はそれほど重要ではありません。 HQLがさらに異なる場合、これはより重要になります。

38
Craig Walker

通常、どのデータでどの入力が使用されるかわからない場合は、基準を使用します。ユーザーが1から50の項目のいずれかを入力できる検索フォームのように、私は彼らが検索するものを知らない。ユーザーが何を検索しているかをチェックする際に、基準にさらに追加するだけで非常に簡単です。そのような状況でHQLクエリを配置するのは少し面倒だと思います。 HQLは、自分が何を望んでいるかを正確に知っているときは素晴らしいです。

34
Arthur Thomas

HQLは、読みやすく、Eclipse Hibernateプラグインなどのツールを使用してデバッグしやすく、ログに記録しやすいです。基準クエリは、実行時に多くの動作が決定される動的クエリを構築するのに適しています。 SQLを知らない場合は、Criteriaクエリの使用を理解できますが、全体的には、事前に必要なものがわかっている場合はHQLを好みます。

31
Brian Deterling

基準は、第2レベルのクエリキャッシュで特別な最適化を利用する自然キー検索を指定する唯一の方法です。 HQLには、必要なヒントを指定する方法がありません。

詳細はこちらをご覧ください:

22
Alex Miller

Criteria Apiは、Hibernateの優れたコンセプトの1つです。私の見解によれば、これらはHQLCriteria Apiを区別できる少数のポイントです

  1. HQLはデータに対して選択操作と非選択操作の両方を実行しますが、基準はデータを選択するためだけであり、基準を使用して非選択操作を実行することはできません。
  2. HQLは静的クエリの実行に適していますが、基準は動的クエリの実行に適しています
  3. HQLはpaginationコンセプトをサポートしていませんが、Criteriaでページネーションを達成できます。
  4. 基準は、HQLよりも実行に時間がかかっていました。
  5. Criteriaでは、動的なクエリ生成のため、SQLインジェクションで安全ですが、クエリが固定またはパラメータ化されているHQLでは、SQLインジェクションから安全ではありません
20
Arvind

私にとって、基準は理解しやすく、動的クエリを作成するのは非常に簡単です。しかし、これまでに言った欠陥は、Select、Proxy、Defaultの3種類のFetchModeしかないため、すべての多対1などの関係をロードするということです。私を:))

Criteriaの2番目の問題は、完全なオブジェクトをロードすることです。つまり、従業員のEmpNameをロードしたいだけで、これを思い付かない場合、完全なEmployeeオブジェクトを作成し、これによりEmpNameを取得できますレポートでは本当にうまく機能しません。 HQLがロードする(関連付け/関係をロードしなかった)ため、パフォーマンスを何度も向上させたい場合。

Criteriaの1つの機能は、HQLのようにurクエリが固定またはパラメーター化されているため、SQLインジェクションに対して安全ではない動的なクエリ生成のため、SQLインジェクションからuを保護することです。

また、ur aspx.csファイルにHQLを記述すると、ur DALと緊密に結合されます。

全体的に私の結論は、レポートのようにHQLなしでは生きられない場所があるので、それらを使用することです。

13
Zafar

両方の長所を活用するには、HQLの表現力と簡潔さ、および基準の動的な性質により、 Querydsl の使用を検討してください。

Querydslは、JPA/Hibernate、JDO、SQL、およびコレクションをサポートしています。

私はQuerydslのメンテナーなので、この答えは偏っています。

12

私にとってCriteriaの最大のメリットはサンプルAPIです。このAPIでは、オブジェクトを渡すことができ、Hibernateはそれらのオブジェクトプロパティに基づいてクエリを作成します。

それに加えて、基準APIには次のような癖があります(休止状態チームはAPIを作り直していると思います)。

  • criteria.createAlias( "obj")は、可能な外部結合の代わりに内部結合を強制します
  • 同じエイリアスを2回作成することはできません
  • 一部のSQL句には、対応する単純な基準がありません(副選択など)
  • 等.

Sql(status = 'blocked'のユーザーから削除)に似たクエリが必要な場合はHQLを使用する傾向があり、文字列の追加を使用したくない場合は基準を使用する傾向があります。

HQLのもう1つの利点は、すべてのクエリを事前に定義でき、さらにそれらをファイルなどに外部化できることです。

11
Miguel Ping

Criteria APIは、クエリフィルターが実行時に動的に適用される場合、動的に生成されたクエリにより適しています。したがって、動的クエリを作成するときに SQLインジェクション攻撃を防ぐ には、Criteria APIが非常に適しています。

基準クエリは表現力が低く、非常に複雑で非効率的な SQL生成クエリ で簡単に終わります。私はかつてCriteria APIがデフォルトのクエリメソッドである大規模なエンタープライズアプリケーションに参加しましたが、広範なコードレビューでさえ、最終的にどのSQLクエリになるかわからないという恐怖を克服できませんでした。

JPQLまたはHQLはより表現力があり、関連する生成されたSQLクエリの予測がはるかに簡単です。また、基準のクエリよりもHQLクエリのレビューがはるかに簡単です。

エンティティクエリのほとんどのユースケースでは、動的なwhere句は必要ないため、動的なクエリの基準を残したまま、ほとんどのクエリをJPQLで実装できます。

エンティティを変更する必要がある場合、JPQLまたはCriteria APIを使用してエンティティを選択することは理にかなっています。それ以外の場合、DTO投影のパフォーマンスが向上します。 詳細はこの記事 をご覧ください。

9
Vlad Mihalcea

Criteria apiは、SQLもHQLも提供しない1つの明確な機能を提供します。すなわち。クエリのコンパイル時チェックを許可します。

9
user1165443

最初はアプリケーションで主にCriteriaを使用していましたが、パフォーマンスの問題によりHQLに置き換えられました。
主に、Criteriaで複数のクエリにつながる複数の結合を持つ非常に複雑なクエリを使用していますが、HQLでは非常に最適化されています。
ケースは、完全なオブジェクトではなく、特定のオブジェクトに対していくつかのプロパティのみを使用することです。 Criteriaでは、問題は文字列の連結でもありました。
HQLでユーザーの名前と姓を表示する必要がある場合、(name || ' ' || surname)は非常に簡単ですが、Crteriaではこれは不可能です。
これを克服するために、必要な結果のためにそのような連結が実装されたメソッドがあったResultTransormersを使用しました。
今日、主に次のようなHQLを使用しています。

String hql = "select " +
            "c.uuid as uuid," +
            "c.name as name," +
            "c.objective as objective," +
            "c.startDate as startDate," +
            "c.endDate as endDate," +
            "c.description as description," +
            "s.status as status," +
            "t.type as type " +
            "from " + Campaign.class.getName() + " c " +
            "left join c.type t " +
            "left join c.status s";

Query query =  hibernateTemplate.getSessionFactory().getCurrentSession().getSession(EntityMode.MAP).createQuery(hql);
query.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
return query.list();

この場合、返されるレコードは必要なプロパティのマップです。

7
Bojan Kraut
  • HQLはデータに対して選択操作と非選択操作の両方を実行しますが、基準はデータの選択のみであり、基準を使用して非選択操作を実行することはできません
  • HQLは静的クエリの実行に適していますが、基準は動的クエリの実行に適しています
  • HQLはページネーションの概念をサポートしていませんが、Criteriaでページネーションを達成できます
  • HQLよりも実行に時間がかかる基準
  • Criteriaでは、動的なクエリ生成のためSQLインジェクションでも安全ですが、HQLではクエリが固定またはパラメータ化されているため、SQLインジェクションから安全ではありません。

ソース

7
Premraj

動的なクエリの基準クエリは、入力に基づいてクエリを作成できます。Hqlクエリの場合、クエリの構造を変更することはできません。

5
user1679378

私はここで死んだ馬を蹴りたくはありませんが、Criteriaクエリが非推奨になったことに言及することは重要です。 HQLを使用します。

4
Eskir

また、動的クエリには基準クエリを使用します。しかし、削除クエリにはhqlを好みます。たとえば、親ID「xyz」の子テーブルからすべてのレコードを削除する場合、HQLによって簡単に実現できますが、条件APIの場合、最初にn個の削除クエリを起動する必要があります(nは子の数)テーブルレコード。

1
Punit Patel

別の方法があります。休止状態の元の構文に基づいてHQLパーサーを作成し、最初にHQLを解析してから、動的パラメーターを動的に挿入したり、HQLクエリに一般的なフィルターを自動的に追加したりすることになりました。うまくいきます!

0
Wallace Peng

この投稿はかなり古いものです。ほとんどの回答は、JPA基準ではなくHibernate基準について述べています。 JPA 2.1では、CriteriaDelete/CriteriaUpdate、およびフェッチする内容を正確に制御するEntityGraphが追加されました。 Javaはオブジェクト指向であるため、基準APIの方が優れています。それがJPAが作成される理由です。 JPQLがコンパイルされると、SQLに変換される前にAST tree(OOモデル)に変換されます。

0
Sunnyday

ここでの答えのほとんどは誤解を招くものであり、Criteria QueriesHQLよりも遅いことを言及していますが、実際にはそうではありません。

深く掘り下げていくつかのテストを実行すると、Criteria Queryが通常のHQLよりもはるかに優れたパフォーマンスを発揮します。

また、Criteria Queryを使用すると、Object Oriented controlが得られますが、これはHQL

詳細については、この答えをお読みください こちら

0
Pritam Banerjee