1. ホーム

[解決済み】JPA OneToOneリレーションを遅延させる方法は?

2022-04-21 04:02:15

質問

私たちが開発しているこのアプリケーションでは、あるビューが特に遅いことに気づきました。そのビューをプロファイリングしたところ、hibernateによって実行されるクエリが1つあり、フェッチするオブジェクトがデータベース内に2つしかないにもかかわらず10秒かかっていることに気づきました。すべて OneToManyManyToMany リレーションは遅延していたので、問題ではありませんでした。実際に実行されたSQLを調べてみると、クエリに80以上の結合があることに気づきました。

さらに検証を進めると、この問題の原因は OneToOneManyToOne エンティティクラス間の関係です。そこで私は、それらを遅延フェッチさせれば問題が解決するのではないかと考えました。しかし @OneToOne(fetch=FetchType.LAZY) または @ManyToOne(fetch=FetchType.LAZY) はうまくいかないようです。例外が発生するか、実際にプロキシオブジェクトに置き換えられておらず、その結果、遅延しています。

どうすればうまくいくのか、何かアイデアはありませんか?なお、私は persistence.xml を使用してリレーションや設定の詳細を定義し、すべてJavaコードで行っています。

どのように解決するのですか?

まず最初に、以下の点について説明します。 KLE の回答です。

  1. 制約のない(Nullable)1対1アソシエーションは、バイトコードインスツルメンテーションなしでプロキシされない唯一のものです。その理由は、オーナーエンティティは、associationプロパティがプロキシオブジェクトを含むべきかNULLを含むべきかを知らなければならず、通常1対1は共有PKを介してマッピングされるため、ベーステーブルの列を見てそれを決定できないため、とにかく熱心にフェッチしなければならず、プロキシの意味がないためである。以下は より詳細 を説明します。

  2. 多対一の関連付けは(もちろん一対多の関連付けも)この問題に悩まされることはありません。所有者エンティティはそれ自身のFKを簡単にチェックできるので (そして1対多の場合、空のコレクションプロキシが最初に作成され、必要に応じて投入されます)、関連付けは怠慢になる可能性があります。

  3. 一対一を一対多で置き換えることは、決して良いアイデアではありません。ユニークな多対一に置き換えることはできますが、他に(より良い)選択肢があるはずです。

ロブ・H の指摘は正しいのですが、モデルによっては実装できない場合があります(例えば、一対一の関連付けである nullable)です。

さて、当初の質問の件ですが。

A) @ManyToOne(fetch=FetchType.LAZY) は正常に動作するはずです。クエリ自体で上書きされてない?を指定することは可能です。 join fetch HQL でフェッチモードを設定するか、または Criteria API で明示的にフェッチモードを設定すると、クラスアノテーションより優先されます。そうでなく、まだ問題がある場合は、クラス、クエリ、および結果の SQL を投稿して、より要領よく会話してください。

B) @OneToOne は、もっと厄介です。もし確実にnullableでないなら、Rob H.の提案に従って、そのように指定してください。

@OneToOne(optional = false, fetch = FetchType.LAZY)

その他、データベースを変更(ownerテーブルに外部キーカラムを追加)できる場合はそうして、"joined"としてマッピングしてください。

@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name="other_entity_fk")
public OtherEntity getOther()

とOtherEntityにあります。

@OneToOne(mappedBy = "other")
public OwnerEntity getOwner()

もしそれができないなら(そしてイーガーフェッチに耐えられないなら)、バイトコードインスツルメンテーションが唯一の選択肢となります。私は、以下の意見に賛成です。 CPerkins しかし、もしあなたが 80!!! が、OneToOneの熱心な関連付けのために結合している場合、これより大きな問題があります :-)。