6

次の明らかに文書化されていない問題が発生しました。

  1. 私は何か悪いことをした
  2. 誰かが同じ問題に遭遇しましたか?
  3. 本当にどこにも文書化されていませんか?または私は何かを逃しましたか?

動作はこれです 次のマッピングを想定します

<class name="org.sample.Foo" table="foo">
    ...
   <many-to-one name="bar" class="org.sample.Bar"/>
</class>


<class name="org.sample.Bar" table="bar" lazy="false">
    ...
</class>

まず、背景として、多対 1 のリレーションのfetch属性の Hibernate のデフォルト値は「 select」である必要があります。これは少なくとも文書化されているものです (見つけたらここにリンクを追加します)。

ただし、これは、参照されるクラスが lazy="true" である場合にのみ当てはまります。

したがって、明らかに上記のマッピングは次のように変換されます (Bar は lazy="false" であるため):

<class name="org.sample.Foo" table="foo">
    ...
   <many-to-one name="bar" class="org.sample.Bar" *fetch="join" />
</class>


<class name="org.sample.Bar" table="bar" lazy="false">
    ...
</class>

では、なぜそれが問題になるのでしょうか。2 つの選択の代わりに、Hibernate は非遅延参照をその「親」を使用して単一の選択でロードします (単一の選択で Bar を使用して Foo をロードします)。

オブジェクトは遅延していないので、これは実際に理にかなっています。ロードしないのはなぜですか?

答えはこうです: Bar が第 2 レベルのキャッシュにある場合はどうなりますか?

<class name="org.sample.Foo" table="foo">
    ...
   <many-to-one name="bar" class="org.sample.Bar" *fetch="join" />
</class>


<class name="org.sample.Bar" table="bar" lazy="false">
    <cache usage="transactional" />
    ...
</class>

その答えは、何も変わらないということです。

どうやら、Hibernate はこのタイプのオブジェクトをロードしてはならないことを理解できるほどスマートであると想定するでしょうが、デフォルトのフェッチが select から join に変更されたため、Hibernate には選択の余地がありません (実際のテーブルを第 2 レベルのキャッシュ、まだ)

そのため、Hibernate は指示されたとおりに実行し、結合を使用して、既に第 2 レベルのキャッシュにあるデータベースからオブジェクトをフェッチします。

私が見つけた解決策は、文字通りマッピングを fetch="select" に変更することです

Bar の 2 番目の選択が実行されようとすると、Hibernate はそれがデータベースに送信されるべきではないことを認識し、キャッシュからフェッチします。1つのクエリのみが実行されます(ウォームアップ後)

4

1 に答える 1

4

私は同じ問題に遭遇し、キャッシュされるすべての多対 1 関係を としてマークしていることに気付きましたfetch="select"。クエリが構築される時点で、Hibernate は要求された Bar のインスタンスが第 2 レベルのキャッシュにあるかどうかを知ることができません (Foo がキャッシュされていないと仮定します)。

于 2010-01-01T17:35:58.547 に答える