5

implementation-result-paging-in-hibernate-getting-total-number-of-rowsの質問は、いくつかの実装上の懸念について、別の質問を引き起こします。

これで、カウントを行うために HQL クエリの一部を再利用する必要があることがわかりました。効率的に再利用するにはどうすればよいでしょうか?

2 つの HQL クエリの違いは次のとおりです。

  1. 選択はcount(?)、pojo またはプロパティ (またはリスト) の代わりに
  2. フェッチは発生しないため、一部のテーブルは結合しないでください
  3. 消えるorder byべき

他に違いはありますか?

この再利用を効率的に達成するためのコーディングのベストプラクティスはありますか(懸念事項: 労力、明確さ、パフォーマンス)?

簡単な HQL クエリの例:

    select       a     from A a join fetch a.b b where a.id=66 order by a.name
    select count(a.id) from A a                  where a.id=66

更新しました

回答を受け取りました:

  • Criteriaを使用(ただし、主に HQL を使用)
  • 文字列クエリの操作 (しかし、誰もが複雑で安全ではないことに同意します)
  • データベースの最適化に頼って、クエリをラップします(ただし、これは安全ではないと感じています)

私は誰かが別の道に沿ってオプションを提供することを望んでいました.文字列の連結に関連しています.
共通部分を使用して両方の HQL クエリを作成できますか?

4

4 に答える 4

3

(SQL?) 基準にプロジェクションを設定して、Hibernate に意図を明確にしようとしましたか? 私は主に基準を使用しているので、これがあなたのケースにどの程度当てはまるかはわかりませんが、使用しています

getSession().createCriteria(persistentClass).
setProjection(Projections.rowCount()).uniqueResult()

そして、Hibernate にキャッシング / 再利用 / スマートなものをそれ自体で理解させます..実際にどれだけのスマートなものを行うかはよくわかりません..これについてコメントしたい人はいますか?

于 2009-10-21T13:47:18.533 に答える
2

まあ、これがベストプラクティスかどうかはわかりませんが、私のプラクティスです:)

クエリとして次のようなものがある場合:

select A.f1,A.f2,A.f3 from A, B where A.f2=B.f2 order by A.f1, B.f3

そして、いくつの結果が得られるか知りたいだけです。実行します。

select count(*) from ( select A.f1, ... order by A.f1, B.f3 )

そして、結果を整数として取得します。結果をPOJOにマッピングしません。

'order by'のように、いくつかの部分を削除するためにクエリを解析します。優れたRDBMSは、クエリを最適化します。

良い質問。

于 2009-10-21T13:00:40.737 に答える
1

いい質問です。これが私が過去にしたことです(あなたがすでに言及した多くのこと):

  1. SELECT句が存在 するかどうかを確認します。
    1. そうでない場合は、追加しますselect count(*)
    2. それ以外の場合は、 DISTINCTまたは集計関数が含まれているかどうかを確認してください。ANTLRを使用してクエリを解析している場合、それらを回避することは可能ですが、かなり複雑です。全体をでラップする方がよいでしょうselect count(*) from ()
  2. 削除するfetch all properties
  3. fetchHQLを文字列として解析している場合は、結合から削除します。ANTLRを使用してクエリを本当に解析している場合は、left join完全に削除できます。考えられるすべての参照をチェックするのはかなり面倒です。
  4. 削除するorder by
  5. group by1.2で行ったことに応じて、削除/調整/する必要がありますhaving

上記は当然HQLにも当てはまります。Criteriaクエリの場合、操作が簡単ではないため、実行できることはかなり制限されます。Criteriaの上にある種のラッパーレイヤーを使用している場合、ANTLR解析結果の(限定された)サブセットと同等の結果になり、その場合は上記のほとんどを適用できます。

通常は現在のページのオフセットと合計数を保持するため、通常は最初に指定された制限/オフセットを使用して実際のクエリを実行し、count(*)返される結果の数が制限以上でオフセットがゼロの場合にのみクエリを実行します(他のすべての場合、私はcount(*)以前に実行したか、とにかくすべての結果を取り戻しました)。もちろん、これは同時変更に関して楽観的なアプローチです。

更新(手作業でHQLを組み立てる)

私はそのアプローチが特に好きではありません。名前付きクエリとしてマップすると、HQLにはビルド時のエラーチェックの利点があります(とにかく統合テスト中に通常行われるものの、SessionFactoryをビルドする必要があるため、技術的にはランタイムです)。実行時に生成されると、実行時に失敗します:-)パフォーマンスの最適化を行うことも簡単ではありません。

もちろん、同じ理由がCriteriaにも当てはまりますが、文字列の連結とは対照的に、APIが明確に定義されているため、失敗するのは少し難しいです。2つのHQLクエリ(ページ1と「グローバルカウント」1)を並行して構築すると、コードの重複(および潜在的にはさらに多くのバグ)が発生したり、その上に何らかのラッパーレイヤーを記述して実行したりする必要があります。どちらの方法も理想からはほど遠いです。また、(APIを介した場合のように)クライアントコードからこれを行う必要がある場合、問題はさらに悪化します。

私は実際にこの問題についてかなり熟考しました。Hibernate-Generic-DAOの検索APIは妥当な妥協案のようです。上記のリンクされた質問に対する私の答えには、より多くの詳細があります。

于 2009-10-21T17:25:03.523 に答える
0

フリーハンドの HQL の状況では、このようなものを使用しますが、これは特定のエンティティに固有のものであるため、再利用できません。

Integer count = (Integer) session.createQuery("select count(*) from ....").uniqueResult();

これを 1 回実行し、ページをめくるまで開始番号を適宜調整します。

基準については、このようなサンプルを使用します

final Criteria criteria = session.createCriteria(clazz);  
            List<Criterion> restrictions = factory.assemble(command.getFilter());
            for (Criterion restriction : restrictions)
                criteria.add(restriction);
            criteria.add(Restrictions.conjunction());
            if(this.projections != null)
                criteria.setProjection(factory.loadProjections(this.projections));
            criteria.addOrder(command.getDir().equals("ASC")?Order.asc(command.getSort()):Order.desc(command.getSort()));
            ScrollableResults scrollable = criteria.scroll(ScrollMode.SCROLL_INSENSITIVE);
            if(scrollable.last()){//returns true if there is a resultset
                genericDTO.setTotalCount(scrollable.getRowNumber() + 1);
                criteria.setFirstResult(command.getStart())
                        .setMaxResults(command.getLimit());
                genericDTO.setLineItems(Collections.unmodifiableList(criteria.list()));
            }
            scrollable.close();
            return genericDTO;

しかし、これは を呼び出すことで毎回カウントを行いますScrollableResults:last()

于 2009-10-21T15:48:03.593 に答える