121

JPAのフェッチ戦略は正確に何を制御しますか? 熱心と怠惰の違いを検出できません。どちらの場合も、JPA/Hibernate は自動的に多対 1 の関係に参加しません。

例: 個人の住所は 1 つです。アドレスは多くの人に属することができます。JPA アノテーション付きエンティティ クラスは次のようになります。

@Entity
public class Person {
    @Id
    public Integer id;

    public String name;

    @ManyToOne(fetch=FetchType.LAZY or EAGER)
    public Address address;
}

@Entity
public class Address {
    @Id
    public Integer id;

    public String name;
}

JPA クエリを使用する場合:

select p from Person p where ...

JPA/Hibernate は、Person テーブルから選択する 1 つの SQL クエリを生成し、次に人物の個別のアドレス クエリを生成します。

select ... from Person where ...
select ... from Address where id=1
select ... from Address where id=2
select ... from Address where id=3

これは、大きな結果セットでは非常に悪いことです。1000 人がいる場合、1001 個のクエリが生成されます (1 つは Person から、1000 は Address とは異なります)。これは、MySQL のクエリ ログを見ているのでわかります。アドレスのフェッチ タイプを熱心に設定すると、JPA/Hibernate が結合で自動的にクエリを実行することを理解していました。ただし、フェッチ タイプに関係なく、リレーションシップに対して個別のクエリが生成されます。

明示的に参加するように指示した場合にのみ、実際に参加します。

select p, a from Person p left join p.address a where ...

ここで何か不足していますか?多対 1 の関係を結合したままにするために、すべてのクエリを手作業でコーディングする必要があります。MySQL で Hibernate の JPA 実装を使用しています。

編集: JPAクエリに影響を与えないようです(Hibernate FAQ hereおよびhereを参照) 。FetchTypeしたがって、私の場合、参加するように明示的に指示しました。

4

8 に答える 8

104

JPA は、フェッチ戦略を選択するためのマッピング アノテーションに関する仕様を提供していません。一般に、関連するエンティティは、以下に示す方法のいずれかで取得できます。

  • SELECT => ルート エンティティに対する 1 つのクエリ + 関連するマップされたエンティティに対する 1 つのクエリ/各ルート エンティティのコレクション = (n+1) クエリ
  • SUBSELECT => ルート エンティティの 1 つのクエリ + 関連するマップされたエンティティの 2 つ目のクエリ/最初のクエリで取得されたすべてのルート エンティティのコレクション = 2 つのクエリ
  • JOIN => ルート エンティティとそれらのマップされたすべてのエンティティ/コレクションの両方を取得するための 1 つのクエリ = 1 つのクエリ

SELECTJOINは 2 つの両極端であり、そのSUBSELECT中間に位置します。ドメインモデルに基づいて適切な戦略を選択できます。

デフォルトSELECTでは、JPA/EclipseLink と Hibernate の両方で使用されます。これは、次を使用してオーバーライドできます。

@Fetch(FetchMode.JOIN) 
@Fetch(FetchMode.SUBSELECT)

休止状態で。また、バッチサイズを使用して調整できるSELECTモードを明示的に設定することもできます。@Fetch(FetchMode.SELECT)@BatchSize(size=10)

EclipseLink の対応する注釈は次のとおりです。

@JoinFetch
@BatchFetch
于 2012-06-18T04:48:10.150 に答える
45

「mxc」がそうです。リレーションをいつfetchType解決するかを指定するだけです。

外部結合を使用して熱心な読み込みを最適化するには、追加する必要があります

@Fetch(FetchMode.JOIN)

あなたのフィールドへ。これは休止状態固有の注釈です。

于 2009-05-08T09:30:21.010 に答える
20

試してみてください:

select p from Person p left join FETCH p.address a where...

JPA2/EclipseLinkと同様に機能しますが、この機能はJPA1にも存在するようです:

于 2011-03-10T15:10:58.897 に答える
7

Hibernate の代わりに EclipseLink を使用すると、「クエリ ヒント」によってクエリを最適化できます。Eclipse Wiki の記事EclipseLink/Examples/JPA/QueryOptimizationを参照してください。

「結合読書」についての章があります。

于 2009-08-20T12:18:38.587 に答える
3

参加するには、複数のことができます (eclipselink を使用)

  • jpqlでは、左結合フェッチを行うことができます

  • 名前付きクエリでは、クエリヒントを指定できます

  • TypedQuery では、次のように言うことができます

    query.setHint("eclipselink.join-fetch", "e.projects.milestones");

  • バッチフェッチのヒントもあります

    query.setHint("eclipselink.batch", "e.address");

見る

http://java-persistence-performance.blogspot.com/2010/08/batch-fetching-optimizing-object-graph.html

于 2014-06-02T19:12:56.607 に答える
1

Person クラスにキークラスが埋め込まれていることを除いて、私はまさにこの問題を抱えていました。私自身の解決策は、それらをクエリに参加させて削除することでした

@Fetch(FetchMode.JOIN)

私の埋め込まれたIDクラス:

@Embeddable
public class MessageRecipientId implements Serializable {

    @ManyToOne(targetEntity = Message.class, fetch = FetchType.LAZY)
    @JoinColumn(name="messageId")
    private Message message;
    private String governmentId;

    public MessageRecipientId() {
    }

    public Message getMessage() {
        return message;
    }

    public void setMessage(Message message) {
        this.message = message;
    }

    public String getGovernmentId() {
        return governmentId;
    }

    public void setGovernmentId(String governmentId) {
        this.governmentId = governmentId;
    }

    public MessageRecipientId(Message message, GovernmentId governmentId) {
        this.message = message;
        this.governmentId = governmentId.getValue();
    }

}
于 2011-12-12T11:04:32.747 に答える
0

私には2つのことが起こります。

まず、アドレスは ManyToOne のことですか? つまり、複数の人が同じアドレスを持つことになります。それらの 1 つに対して編集された場合、それらすべてに対して編集されます。それはあなたの意図ですか?アドレスの 99% は「プライベート」です (1 人だけに属しているという意味で)。

第二に、Person エンティティに他の熱心な関係がありますか? 私の記憶が正しければ、Hibernate はエンティティで 1 つの熱心な関係しか処理できませんが、それは古い情報である可能性があります。

これがどのように機能するかについてのあなたの理解は、私が座っている場所から本質的に正しいからです。

于 2009-01-20T22:24:56.423 に答える