18

Hibernate3を使用してWebアプリケーションを作成しています。

それで、しばらくして、何かが遅いことに気づきました。そこで、hibernateプロファイラーをテストしたところ、hibernateが単純な操作のために不当に多くのdb呼び出しを行うことがわかりました。その理由はもちろん、オブジェクトをロードし(このオブジェクトには複数の「親」があります)、これらの「親」には他の「親」があります。つまり、基本的なオブジェクトが必要なだけなのに、基本的に休止状態はそれらすべてをロードします。さて、私は遅延読み込みを調べました。私はMVCWebアプリを持っているので、これは私をLazyloading-exceptionに導きます。

だから今、私はこれに対する私の最善のアプローチが何であるかについて少し混乱しています。基本的に必要なのは、オブジェクトの1つのフィールドを更新することだけです。私はすでにオブジェクトキーを持っています。

私がすべきこと:1。遅延読み込みを掘り下げます。そして、オープンセッションビュー用にアプリを書き直しますか?2.遅延読み込みを掘り下げます。そして、私のdaoをより具体的に書き直します。たとえば、各ユースケースに必要なものだけでインスタンス化されたオブジェクトを返すDAOメソッドを作成しますか?余分な方法がたくさんある可能性があります...3。休止状態をスクラッチして、自分で実行しますか?4.カントは今他の解決策を本当に考えています。助言がありますか?

ベストプラクティスは何ですか?

4

3 に答える 3

30
  • 本当に必要でない限り、結合を使用しないでください。遅延読み込みを使用することも、関連付けに第 2 レベルのキャッシュを使用することもできません。
  • 大きなコレクションには lazy="extra" を使用します。要求するまですべての要素を取得しません。たとえば、DB から要素を取得せずに size() メソッドを使用することもできます。
  • 必要になるまで選択クエリを発行しないため、可能な場合は load() メソッドを使用します。たとえば、Book と Author があり、それらを関連付けたい場合、select は発行されず、単一の挿入のみが発行されます。

    Book b = (Book) session.load(Book.class, bookId);
    Author a = (Author) session.load(Author.class, authorId);
    b.setAuthor(a);
    session.save(b);
    
  • 各クエリ中に解析されないように、(hbm ファイルまたは @NamedQuery で) 名前付きクエリを使用します。必要になるまで Criteria API を使用しないでください (この場合、PreparedStatement キャッシュを使用できなくなります)。

  • OSIV は必要な場合にのみデータをロードするため、Web アプリで OSIV を使用します。
  • selects-only: には読み取り専用モードを使用しますsession.setReadOnly(object, true)。これにより、Hibernate は選択されたエンティティの元のスナップショットを永続的なコンテキストに保持せず、さらにダーティ チェックを行うことができます。
  • ユーザーの第 2 レベルのキャッシュと、ほとんどが読み取り専用のデータ用のクエリ キャッシュ。
  • AUTO の代わりに FlushMode.COMMIT を使用して、Hibernate が更新前に select を発行しないようにしますが、古いデータが書き込まれる可能性があることに備えてください (楽観的ロックが役立ちます)。
  • エンティティ/コレクションごとに個別のクエリを発行するのではなく、一度に複数のエンティティ/コレクションを選択するために、バッチ フェッチ (バッチサイズ) を見てください。
  • 必要なフィールドのみを取得するために、「select new Entity(id, someField) from Entity」のようなクエリを実行します。結果トランスフォーマーを見てください。
  • 必要に応じてバッチ操作 (削除など) を使用する
  • ネイティブ クエリを使用する場合は、無効にするキャッシュ領域を明示的に指定します (デフォルトではすべて)。
  • ツリー状構造の具体化されたパスとネストされたセットを見てください。
  • c3p0.max_statementsプールで PreparedStatement キャッシュを有効にし、デフォルトでオフになっている場合は DB のステートメント キャッシュを有効にするために設定します。
  • 可能であれば StatelessSession を使用してください。これにより、ダーティ チェック、カスケード、インターセプターなどを克服できます。
  • setMaxResults()コレクションへの結合を含むクエリと一緒にページネーション ( , )を使用しないでくださいsetFirstResult()。これにより、データベースからすべてのレコードが取得され、Hibernate によってメモリ内でページネーションが行われます。ページネーションが必要な場合は、理想的には結合を使用しないでください。回避できない場合は、バッチ フェッチを使用してください。

実際にはたくさんのトリックがありますが、現時点ではそれ以上思い出せません。

于 2012-04-25T17:26:13.307 に答える
1

Hibernate マニュアルのこのセクションを確認してください。

「...不当に多くのdb呼び出し...」という元の問題は、彼らが「N + 1選択問題」と呼んでいるもののインスタンスであると思います。もしそうなら、彼らはそれに対処する方法の選択肢を持っています.

  1. フェッチ タイプを Join にします。次に、中間コレクションがないと仮定して、複数の結合を持つ単一の選択を行います。
  2. 遅延読み込みを行います。
  3. おそらく他にも、たとえば私が経験したことのない FetchProfiles などがあります。

最初の 2 つは関連付けレベルで指定でき、フェッチ タイプはクエリ レベルでオーバーライドできます。これらのツールを使用すると、必要なことだけをクエリに実行させることができ、それ以上は実行できず、「適切な」SQL クエリで実行できるはずです。

于 2012-04-25T16:30:45.637 に答える